27 de set. de 2015

Python - Hashlib e HMAC

O HMAC (Hash-base Message Authentication Code) é usado para verificar a integridade de informações e arquivos. Mecanismos que verificam a integridade baseados em uma chave secreta são usualmente chamados de MAC (message authentication codes), baseados em 2 partes que compartilham 2 chaves secretas para validar a informação transmitida. O HMAC usa uma variedade de algoritmos como: MD5, SHA1, SHA256, RIPEMD-128/160, entre outros.

exemplo_hmac.py:
import hmac
import hashlib
# o hmac.new possui 3 argumentos: chave, msg e o modulo do hash
gerar_resumo=hmac.new('chave_secreta','',hashlib.md5)
f=open('arquivo.txt','rb')
try:
    while True:
        bloco=f.read(1024)
        if not bloco:
           break
        gerar_resumo.update(bloco)
finally:
    f.close()
resumo=gerar_resumo.hexdigest()
print resumo

Os dados são criptografados usando o hash atual combinado com uma chave secreta: hash(K XOR 5c5c5c… + hash(K XOR 363636… + msg)), sendo K a chave secreta usada para comprimir blocos de dados através da função hash  denotada por B (geralmente de 64 bytes):
>>> from md5 import md5
>>> print md5().block_size
64

Tudo isso resulta em um pequeno resumo de tamanho fixo. Por exemplo, aplicando um hash MD5 em um arquivo de 1GB ou qualquer outro tamanho resultará sempre em um resumo com o mesmo tamanho de 128 bits e 32 caracteres hexadecimais: 

Verificando a integridade com o hashlib e md5sum:
>>>import hashlib
>>>hashlib.md5(open('arquivo.txt', 'r').read()).hexdigest()
'530477e014c4f7b7296939da49a52a62'
$ md5sum arquivo.txt 
530477e014c4f7b7296939da49a52a62  arquivo.txt

Sabemos que o MD5 é vulnerável aos ataques de colisão, que é feito gerando uma colisão (conjunto de dados com o mesmo resultado de hash). Porém isso não compromete o uso do HMAC pois as colisões do MD5 dependem de condições iniciais. Mesmo se: MD5(a)==MD5(b), MD5(x+a)!=MD5(x+b) e se uma chave HMAC em branco x comece com 64 bytes de zeros o XOR terminará com 36, resultando em um primeiro bloco MD5 de 363636... O MD5 e SHA1 foram desenvolvidos para serem rápidos, se tornando uma vantagem para o atacante que decide usar a força bruta para quebrar o hash, podendo testar cerca de 400 bilhões de chaves por segundo.

Entendendo a colisão:
Nesse exemplo tirado desse site,  temos 2 executáveis diferentes com a mesma identidade:
hello - MD5 Sum: da5c61e1edc0f18337e46418e48c1290
erase - MD5 Sum: da5c61e1edc0f18337e46418e48c1290

Esses dois arquivos foram gerados explorando a estrutura de blocos da função MD5, onde um arquivo de entrada será anexado primeiro (seu tamanho será múltiplo de 64 bytes), depois ele é dividido em blocos individuais de 64 bytes. O hash MD5 é computado através dos estados das sequencias de 16-bytes de acordo com a regra: si+1 = f(si, Mi), onde f é uma função fixa com estado inicial s0 fixo (vetor de inicialização). O estado final sn é o hash MD5.
O método de Wang e Yu usa um vetor de inicialização s para encontrar dois pares de blocos M, M' e N,N' assim como f(f(s,M),M')=f(f(s,N),N'). Assim é possível encontrar pares de arquivos de tamanhos arbitrários, que são idênticos , exceto pelos 128 bytes no meio do arquivo e que possuem hash MD5 idênticas.

* Fontes:
https://pymotw.com/2/hmac/
http://dankaminsky.com/2015/05/07/the-little-mac-attack/
http://tools.ietf.org/html/rfc2104.html
http://benlog.com/2008/06/19/dont-hash-secrets/

0 comentários:

Postar um comentário