Python – Criando senhas criptografadas para usuários Linux

PythonCryptYoctoProject_cleitonbueno.com

A um tempo atras precisei implementar uma receita do Yocto Project onde alguns usuários deveriam ser criados, porém enfrentei dois problemas.

1) Teria que criar algumas senhas e criptografar elas e como eram usuários Unix teria que ser no formato “compativel” com /etc/shadow

2) Pode ser que o operador pude-se adicionar a senha ou alterar sem criar usuário e/ou executar um passwd

Sem muito esforço já havia utilizado a crypt.h em C e nativamente o Python possui o modulo crypt, deve-se atentar sobre as versões Python 2.6, 2.7, 3.2 e Python 3.3 ou superior, pois na versão <= 3.2 existe uma implementação e na versão superior a 3.2 possui a mesma porém com alguns adendos, da implementação do crypt usando Python 2.6, 2.7 ou 3.2 irá funcionar nas versões mais nova o contrario não.

Olhe nos links abaixo a diferença.

https://docs.python.org/2/library/crypt.html

https://docs.python.org/3.3/library/crypt.html

Vamos ao primeiro exemplo básico e já funcional:

#! /usr/bin/python

import crypt

def gerar_passwd():
      minha_senha = raw_input('Digite a senha: ')
      senha_gerada = crypt.crypt(minha_senha, "$6$SalG4ndo$")
      return senha_gerada

if __name__ == '__main__':
      print gerar_passwd()

Executando o script acima e para a senha 123456:

$ python gerarsenha.py
Digite a senha: 123456
$6$SalG4ndo$sS2p7vKgvM/vEsKrceXlFe.9YAbDz4jB7ify.l0FEK84jHGAt5UUqkJWRNhwTv0WfyW

$ sudo cat /etc/shadow | grep user1
user1:$6$SalG4ndo$sS2p7vKgvM/vEsKrceXlFe.9YAbDz4jB7ify.l0FEK84jHGAt5UUqkJWRNhwTv0WfyW:16441:0:99999:7:::

Ok, bateu, mas que magia negra é aquele “$6$SalG4ndo$“? Vamos ver agora.

Primeiro que não foi de primeira que cheguei no hash que esperava, e segundo que houve uma analise necessária para obter os parâmetros corretos para gerar o hash correto para o /etc/shadow em uso que pode variar e deve-se atentar aos 3 itens a seguir.

1) Verificar no seu Linux qual o método de encriptação configurado, pode obter facilmente com o comando abaixo:

$ cat /etc/login.defs | grep ^ENCRYPT_METHOD
ENCRYPT_METHOD SHA512

2)  Eu não comentei do crypt do Linux? Vamos ver este cara que é a base para entendermos o crypt do Python

$ man 3 crypt
...
NOTES
   Glibc notes
       The glibc2 version of this function supports additional encryption algorithms.

       If salt is a character string starting with the characters "$id$" followed by a string terminated by "$":

              $id$salt$encrypted

       then instead of using the DES machine, id identifies the encryption method used and this then determines how the rest of the
       password string is interpreted.  The following values of id are supported:

              ID  | Method
              ─────────────────────────────────────────────────────────
              1   | MD5
              2a  | Blowfish (not in mainline glibc; added in some
                  | Linux distributions)
              5   | SHA-256 (since glibc 2.7)
              6   | SHA-512 (since glibc 2.7)

       So $5$salt$encrypted is an SHA-256 encoded password and $6$salt$encrypted is an SHA-512 encoded one.

       "salt" stands for the up to 16 characters following "$id$" in the salt.  The encrypted part of the password  string  is  the
       actual computed password.  The size of this string is fixed:

       MD5     | 22 characters
       SHA-256 | 43 characters
       SHA-512 | 86 characters

       The  characters  in  "salt"  and  "encrypted"  are drawn from the set [a–zA–Z0–9./].  In the MD5 and SHA implementations the
       entire key is significant (instead of only the first 8 bytes in DES).

Eu cortei boa parte do man e peguei apenas o que analisei para entender do que precisaria. Pode ver completo no link a seguir.

http://linux.die.net/man/3/crypt

3) Precisaria então algo assim no crypt do Python:

#! /usr/bin/python

print crypt.crypt("123456","$6$salt$")

"""
Onde:
    "123456" minha senha
    $6 defini ser SHA512 que vi no ENCRYPT_METHOD do /etc/login.defs
    $salt string para "salgar" atrapalhar o algoritmo para gerar o hash da senha

"""

Você pode ser mais hardcore e fazer direto no terminal com Python, usando o poder/facilidade do Python para isso:

$ python -c 'import crypt; print crypt.crypt("123456","$6$salt$")'
$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w.igcOo1R7vBYR65JquIQ/7siC7VRpmteKvZmfSkNc69.

Então os métodos disponíveis e mais usados são:

$1 : MD5

$5 : SHA256

$6 : SHA512

$salt : String para embaralhar

Eu nunca usei “salt” como string, alguns casos gerei randomicamente, adaptei nosso primeiro exemplo para o a seguir onde a string salt é gerada randomicamente com 16 caracteres e estou usando encode base-64 ([A-Za-z0-9], “/” e “+”), pode usar outros modos de encode como hex para hexadecimal, e logo em seguida eu fatio do 2º ao 9º caractere ficando com 8 caracteres e adiciono $6$ e $ ao final da string.

#! /usr/bin/python

import crypt
import os


"""
   @Generate random string to salt with 8 characters
"""
custom_salt = "$6$"+os.urandom(16).encode('base64')[2:10]+"$"


def gerar_passwd():
    minha_senha = raw_input('Digite a senha: ')
    print("Salt: %s" % custom_salt)
    hash_senha = crypt.crypt(minha_senha,custom_salt)
    return hash_senha

if __name__ == '__main__':
    print("HASH: %s" % gerar_passwd())

Executando:

 $ python gerarsenha.py
Digite a senha: 123456
Salt: $6$HLqZzbwe$
HASH: $6$HLqZzbwe$/DPwX2tsKDpigk0yYNw9RAO65BBS5nWeqmYJbvHpM/hR8j6mwOE5gqrC2ORC1siWJY7UfJOmd9B8xwBfyPh.d1

E assim ficou o script dentro da distribuição que gerei com Yocto Project e que também pode ser chamada para as senhas dos usuários já criados e que pode ser utilizado para qualquer Linux.

Espero que tenham gostado, futuramente em um artigo de Yocto Project vou mostrar como adicionar um usuário e poder já inserir esta senha criada em uma receita.

Até a próxima!

Referências

https://docs.python.org/2/library/crypt.html

https://docs.python.org/3.3/library/crypt.html

http://linux.die.net/man/3/crypt

http://cleitonbueno.com/yocto-project-introducao/

http://www.gnu.org/software/libc/manual/html_node/crypt.html

Share Button

CC BY-NC-SA 4.0 Python – Criando senhas criptografadas para usuários Linux by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.