Hash, sal, bcrypt e Argon2: o que faz com a tua palavra-passe um site bem feito

Publicado a por David Carrero

Um site bem feito não sabe a tua palavra-passe. Não é que não queira: é que não pode.

Soa a truque, porque de cada vez que a escreves o sistema deixa-te entrar, e para te deixar entrar tem de verificar alguma coisa. Mas verificar não é saber. O servidor guarda uma impressão digital calculada a partir da tua palavra-passe; quando escreves, volta a calcular a impressão e compara. Se coincidirem, entras. Em momento algum é preciso que a palavra-passe esteja escrita seja onde for.

Daí sai o sinal mais claro para distinguir um serviço sério de um que não o é: se ao esqueceres-te dela ta enviam por email, tinham-na guardada. E o que está guardado acaba, mais cedo ou mais tarde, nas mãos de outra pessoa.

1979 a ideia de não as guardar — e a de o fazer devagar

Em 1979, Robert Morris e Ken Thompson publicaram na Communications of the ACM «Password Security: A Case History», onde contavam o que tinham feito no Unix. É um relato do que aprenderam, e nele ficam assentes duas ideias que hoje damos por evidentes.

A primeira não foram eles que a inventaram — guardar o hash em vez da palavra-passe já se fazia antes —, mas explicaram-na melhor do que ninguém: não guardar a palavra-passe, guardar o seu hash. Uma função que converte a tua palavra-passe num valor de aspecto arbitrário e que não se pode desandar: do hash não se regressa à palavra-passe.

A segunda é mesmo deles: o sal. Um valor aleatório diferente para cada utilizador, que se mistura com a palavra-passe antes de calcular o hash. Sem sal, duas pessoas com a mesma palavra-passe têm o mesmo hash — o ficheiro roubado transforma-se num jogo de encontrar repetidos — e, pior, alguém pode pré-calcular uma tabela gigantesca uma única vez e usá-la contra todas as bases de dados do mundo. O sal não torna a tua palavra-passe mais difícil de adivinhar: faz com que adivinhá-la não sirva de nada a mais ninguém.

Mas nesse mesmo artigo há uma terceira ideia, muito menos citada, e é a que importa aqui: fizeram a função deliberadamente lenta. Não por descuido. De propósito. Cifrar uma palavra-passe custava muito mais do que tecnicamente era preciso, porque a quem entra uma vez por manhã tanto lhe faz, e a quem experimenta milhões de candidatas não.

Está ali o assunto todo, numa frase com quase cinquenta anos.

Porque é que a lentidão é a única defesa honesta

Quase todas as defesas informáticas são assimétricas: custam pouco a quem se defende e muito a quem ataca. Cifrar é barato; decifrar sem a chave é inviável. O defensor joga com vantagem estrutural.

O armazenamento de palavras-passe não. Aqui defensor e atacante executam exactamente a mesma função. Tu calculas o hash para verificar que acertaste; ele calcula-o para verificar se acertou. É a única corrida da segurança onde os dois correm com as mesmas pernas.

Quando não consegues correr mais do que o teu rival, resta uma jogada: encarecer a pista para os dois. Tu pagas esse custo uma vez por início de sessão. Ele, uma vez por tentativa. Como precisa de ordens de grandeza mais tentativas do que tu, a mesma factura afecta-vos de forma incomparável. É isso que faz um hash de palavras-passe.

Por isso é que as funções rápidas e óptimas para outras coisas — o SHA-256, por exemplo — são uma escolha péssima aqui. São rápidas. Rápido é exactamente o que não queremos.

1999 bcrypt, e o custo como peça ajustável

O problema de uma função lenta é que o hardware não fica quieto. O que em 1979 era lento, mais tarde é instantâneo. Uma defesa calibrada contra os computadores de uma década envelhece sozinha, sem que ninguém lhe toque.

Em 1999, Niels Provos e David Mazières apresentaram o bcrypt na USENIX Annual Technical Conference, com um título que diz logo tudo: A Future-Adaptable Password Scheme.

A ideia: que o custo não esteja na função, mas num parâmetro. O bcrypt tem um factor de custo que és tu que decides e que fica guardado junto ao hash. Se o hardware ficar muito mais rápido, sobes o número e as palavras-passe novas voltam a custar o que devem, sem mudar de algoritmo.

É um desenho que assume a sua própria obsolescência e se prepara para ela. Há pouquíssimo software que faça isso.

2009 scrypt, e a descoberta de que o tempo não chega

O bcrypt encarece o tempo de cálculo, e resultou. Até que o atacante deixou de usar o mesmo tipo de máquina que o defensor.

Um servidor tem uns poucos núcleos rápidos e de uso geral. Uma GPU tem uma barbaridade de núcleos pequenos a fazer o mesmo em paralelo, e um ASIC vai mais longe: silício fabricado para executar uma única operação. Se a tua defesa consiste em «esta operação custa X», alguém pode construir hardware que faça muitos X ao mesmo tempo. O defensor continua com o servidor dele.

Em 2009, Colin Percival apresentou o scrypt com outro argumento: Stronger Key Derivation via Sequential Memory-Hard Functions. Se o custo está só no cálculo, paraleliza-se. Mas a memória não é oferecida. Obriga a função a usar muita RAM e a percorrê-la de forma que não se possa contornar, e de repente o atacante não pode multiplicar núcleos: cada núcleo precisaria da sua própria memória. E os núcleos de uma GPU têm muita potência e muito pouca RAM para cada um.

Percival não encareceu a operação. Encareceu o hardware necessário para a repetir em massa. É uma mudança de nível: ataca-se o orçamento do atacante, não o relógio dele.

2015 Argon2, e o fim do debate

Existirem várias opções razoáveis não ajudava ninguém a escolher. Por isso a comunidade criptográfica fez o que costuma fazer quando quer arrumar um assunto: um concurso público. A Password Hashing Competition recebeu candidatos, submeteu-os a análise aberta durante anos e em 2015 proclamou vencedor o Argon2.

O Argon2 herda as duas lições: custo em tempo e custo em memória, ambos ajustáveis em separado, mais o número de fios de execução. Não é magia. É a síntese arrumada de 1979, 1999 e 2009, revista por gente cujo trabalho consistia em tentar parti-la.

O que isto significa para ti

Quase nada disto está nas tuas mãos, e convém dizê-lo: o hash é o site que o escolhe, não tu. Podes ter a melhor palavra-passe do mundo e guardarem-ta em texto simples num Excel.

Mas o outro lado da equação depende mesmo de ti. Todo este edifício — o sal, o custo, a memória — serve para encarecer cada tentativa do atacante. O que decide de quantas tentativas ele precisa é a tua palavra-passe. Se estiver num dicionário, nenhuma função lenta te salva: cai logo nas primeiras. Se for comprida e não se parecer com nada, esse preço por tentativa multiplica-se por um número de tentativas que não cabe no tempo disponível.

Por isso é que o nosso gerador mede bits de entropia e não percentagens, e por isso é que o verificador procura a tua palavra-passe em dicionários antes de contar símbolos. Eles põem o preço por tentativa; tu pões o número de tentativas. Nenhuma das duas metades funciona sem a outra.

E sim: continua a ser a mesma pergunta de sempre. Só que agora, do outro lado, alguém tenta respondê-la muitas vezes por segundo, e andamos desde 1979 a tentar que cada uma dessas vezes lhe custe dinheiro.


Fontes: R. Morris e K. Thompson, «Password Security: A Case History», Communications of the ACM, 1979 · N. Provos e D. Mazières, «A Future-Adaptable Password Scheme», USENIX Annual Technical Conference, 1999 (bcrypt) · C. Percival, «Stronger Key Derivation via Sequential Memory-Hard Functions», 2009 (scrypt) · Password Hashing Competition, vencedor Argon2, 2015.

← Voltar ao blog