Hashing seguro com Python Hashlib

Este tutorial ensinará como criar hashes seguros usando a funcionalidade integrada do módulo hashlib do Python.

Compreender a importância do hash e como calcular hashes seguros de forma programática pode ser útil, mesmo que você não trabalhe com segurança de aplicativos. Mas por que?

Bem, ao trabalhar em projetos Python, você provavelmente encontrará instâncias em que está preocupado em armazenar senhas e outras informações confidenciais em bancos de dados ou arquivos de código-fonte. Nesses casos, é mais seguro executar o algoritmo de hash em informações confidenciais e armazenar o hash em vez das informações.

Neste guia, abordaremos o que é hash e como ele difere da criptografia. Também examinaremos as propriedades das funções hash seguras. Em seguida, usaremos algoritmos comuns de hash para calcular o hash do texto sem formatação em Python. Para fazer isso, usaremos o módulo interno hashlib.

Por tudo isso e muito mais, vamos começar!

O que é hash?

O processo de hash recebe uma string de mensagem e fornece uma saída de comprimento fixo chamada hash. O que significa que o comprimento do hash de saída para um determinado algoritmo de hash é fixo – independentemente do comprimento da entrada. Mas como isso é diferente da criptografia?

Na criptografia, a mensagem ou texto simples é criptografado usando um algoritmo de criptografia que fornece uma saída criptografada. Podemos então executar o algoritmo de descriptografia na saída criptografada para recuperar a string da mensagem.

No entanto, o hash funciona de maneira diferente. Acabamos de aprender que o processo de criptografia é invertível, pois você pode ir da mensagem criptografada para a mensagem não criptografada e vice-versa.

Ao contrário da criptografia, o hash não é um processo invertível, o que significa que não podemos ir do hash para a mensagem de entrada.

Propriedades das funções de hash

Vamos examinar rapidamente algumas propriedades que as funções de hash devem satisfazer:

  • Determinístico: As funções hash são determinísticas. Dada uma mensagem m, o hash de m é sempre o mesmo.
  • Resistente à pré-imagem: já abordamos isso quando dissemos que o hash não é uma operação invertível. A propriedade de resistência à pré-imagem afirma que é inviável encontrar a mensagem m do hash de saída.
  • Resistente à colisão: Deve ser difícil (ou computacionalmente inviável) encontrar duas cadeias de mensagens diferentes m1 e m2 de modo que o hash de m1 seja igual ao hash de m2. Essa propriedade é chamada de resistência à colisão.
  • Resistente à segunda pré-imagem: Isso significa que, dada uma mensagem m1 e o hash correspondente m2, é inviável encontrar outra mensagem m2 tal que hash(m1) = hash(m2).
  Como adicionar e excluir perfis de usuário Disney +

Módulo hashlib do Python

O módulo hashlib integrado do Python fornece implementações de vários algoritmos de resumo de hash e mensagem, incluindo os algoritmos SHA e MD5.

Para usar os construtores e as funções integradas do módulo hashlib do Python, você pode importá-lo para o seu ambiente de trabalho da seguinte forma:

import hashlib

O módulo hashlib fornece as constantes algoritmos_disponíveis e algoritmos_garantidas, que denotam o conjunto de algoritmos cujas implementações estão disponíveis e são garantidas em uma plataforma, respectivamente.

Portanto, algoritmos_garantidos é um subconjunto de algoritmos_disponível.

Inicie um Python REPL, importe hashlib e acesse as constantes algoritmos_available e algoritmos_garantidas:

>>> hashlib.algorithms_available
# Output
{'md5', 'md5-sha1', 'sha3_256', 'shake_128', 'sha384', 'sha512_256', 'sha512', 'md4', 
'shake_256', 'whirlpool', 'sha1', 'sha3_512', 'sha3_384', 'sha256', 'ripemd160', 'mdc2', 
'sha512_224', 'blake2s', 'blake2b', 'sha3_224', 'sm3', 'sha224'}
>>> hashlib.algorithms_guaranteed
# Output
{'md5', 'shake_256', 'sha3_256', 'shake_128', 'blake2b', 'sha3_224', 'sha3_384', 
'sha384', 'sha256', 'sha1', 'sha3_512', 'sha512', 'blake2s', 'sha224'}

Vemos que algoritmos_garantidos é de fato um subconjunto de algoritmos_disponíveis

Como criar objetos hash em Python

Em seguida, vamos aprender como criar objetos hash em Python. Calcularemos o hash SHA256 de uma string de mensagem usando os seguintes métodos:

  • O construtor genérico new()
  • Construtores específicos do algoritmo

Usando o construtor new()

Vamos inicializar a string da mensagem:

>>> message = "etechpt.com is awesome!"

Para instanciar o objeto hash, podemos usar o construtor new() e passar o nome do algoritmo conforme mostrado:

>>> sha256_hash = hashlib.new("SHA256")

Agora podemos chamar o método update() no objeto hash com a string da mensagem como argumento:

>>> sha256_hash.update(message)

Se você fizer isso, encontrará um erro, pois os algoritmos de hash só podem funcionar com strings de bytes.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Unicode-objects must be encoded before hashing

Para obter a string codificada, você pode chamar o método encode() na string do método e, em seguida, usá-lo na chamada do método update(). Depois de fazer isso, você pode chamar o método hexdigest() para obter o hash sha256 correspondente à string da mensagem.

sha256_hash.update(message.encode())
sha256_hash.hexdigest()
# Output:'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'

Em vez de codificar a string da mensagem usando o método encode(), você também pode defini-la como uma string de bytes prefixando a string com b da seguinte forma:

message = b"etechpt.com is awesome!"
sha256_hash.update(message)
sha256_hash.hexdigest()
# Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'

O hash obtido é o mesmo que o hash anterior, o que confirma a natureza determinística das funções hash.

  Corrigir o erro do Xbox One 0x80a40019

Além disso, uma pequena alteração na string da mensagem deve fazer com que o hash mude drasticamente (também conhecido como “efeito avalanche”).

Para verificar isso, vamos mudar o ‘a’ em ‘awesome’ para ‘A’ e calcular o hash:

message = "etechpt.com is Awesome!"
h1 = hashlib.new("SHA256")
h1.update(message.encode())
h1.hexdigest()
# Output: '3c67f334cc598912dc66464f77acb71d88cfd6c8cba8e64a7b749d093c1a53ab'

Vemos que o hash muda completamente.

Usando o Construtor Específico do Algoritmo

No exemplo anterior, usamos o construtor genérico new() e passamos “SHA256” como o nome do algoritmo para criar o objeto hash.

Em vez de fazer isso, também podemos usar o construtor sha256() conforme mostrado:

sha256_hash = hashlib.sha256()
message= "etechpt.com is awesome!"
sha256_hash.update(message.encode())
sha256_hash.hexdigest()
# Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'

O hash de saída é idêntico ao hash que obtivemos anteriormente para a string de mensagem “etechpt.com is awesome!”.

Explorando os atributos de objetos hash

Os objetos hash têm alguns atributos úteis:

  • O atributo digest_size denota o tamanho do resumo em bytes. Por exemplo, o algoritmo SHA256 retorna um hash de 256 bits, equivalente a 32 bytes
  • O atributo block_size refere-se ao tamanho do bloco usado no algoritmo de hash.
  • O atributo name é o nome do algoritmo que podemos usar no construtor new(). Pesquisar o valor desse atributo pode ser útil quando os objetos de hash não têm nomes descritivos.

Podemos verificar esses atributos para o objeto sha256_hash que criamos anteriormente:

>>> sha256_hash.digest_size
32
>>> sha256_hash.block_size
64
>>> sha256_hash.name
'sha256'

A seguir, veremos algumas aplicações interessantes de hash usando o módulo hashlib do Python.

Exemplos Práticos de Hashing

Verificando a Integridade do Software e Arquivos

Como desenvolvedores, baixamos e instalamos pacotes de software o tempo todo. Isso é verdade independentemente de você estar trabalhando na distribuição Linux ou em um Windows ou Mac.

No entanto, alguns espelhos para pacotes de software podem não ser confiáveis. Você pode encontrar o hash (ou soma de verificação) ao lado do link de download. E você pode verificar a integridade do software baixado calculando o hash e comparando-o com o hash oficial.

  Como ser desbanido do Tinder

Isso também pode ser aplicado a arquivos em sua máquina. Mesmo a menor alteração no conteúdo do arquivo alterará drasticamente o hash, você pode verificar se um arquivo foi modificado verificando o hash.

Aqui está um exemplo simples. Crie um arquivo de texto ‘my_file.txt’ no diretório de trabalho e adicione algum conteúdo a ele.

$ cat my_file.txt
This is a sample text file.
We are  going to compute the SHA256 hash of this text file and also
check if the file has been modified by
recomputing the hash.

Você pode então abrir o arquivo no modo binário de leitura (‘rb’), ler o conteúdo do arquivo e calcular o hash SHA256 conforme mostrado:

>>> import hashlib
>>> with open("my_file.txt","rb") as file:
...     file_contents = file.read()
...     sha256_hash = hashlib.sha256()
...     sha256_hash.update(file_contents)
...     original_hash = sha256_hash.hexdigest()

Aqui, a variável original_hash é o hash de ‘my_file.txt’ em seu estado atual.

>>> original_hash
# Output: '53bfd0551dc06c4515069d1f0dc715d002d451c8799add29f3e5b7328fda9f8f'

Agora modifique o arquivo ‘my_file.txt’. Você pode remover o espaço em branco inicial extra antes da palavra ‘indo’. 🙂

Calcule o hash novamente e armazene-o na variável computed_hash.

>>> import hashlib
>>> with open("my_file.txt","rb") as file:
...     file_contents = file.read()
...     sha256_hash = hashlib.sha256()
...     sha256_hash.update(file_contents)
...     computed_hash = sha256_hash.hexdigest()

Você pode então adicionar uma instrução assert simples que afirma se o computed_hash é igual ao original_hash.

>>> assert computed_hash == original_hash

Se o arquivo for modificado (o que é verdade neste caso), você deve obter um AssertionError:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Você pode usar hash ao armazenar informações confidenciais, como senhas em bancos de dados. Você também pode usar hash na autenticação de senha ao conectar-se a bancos de dados. Valide o hash da senha inserida com o hash da senha correta.

Conclusão

Espero que este tutorial tenha ajudado você a aprender sobre como gerar hashes seguros com Python. Aqui estão as principais conclusões:

  • O módulo hashlib do Python fornece implementações prontas para uso de vários algoritmos de hash. Você pode obter a lista de algoritmos garantidos em sua plataforma usando hashlib.algorithms_guaranteed.
  • Para criar um objeto hash, você pode usar o construtor genérico new() com a sintaxe: hashlib.new(“algo-name”). Como alternativa, você pode usar os construtores correspondentes aos algoritmos de hash específicos, como: hashlib.sha256() para o hash SHA 256.
  • Depois de inicializar a string de mensagem a ser hash e o objeto hash, você pode chamar o método update() no objeto hash, seguido pelo método hexdigest() para obter o hash.
  • O hashing pode ser útil ao verificar a integridade de artefatos e arquivos de software, armazenar informações confidenciais em bancos de dados e muito mais.

Em seguida, aprenda como codificar um gerador de senha aleatório em Python.