Qual função de hash criptográfico devo escolher?

137

A estrutura .NET é fornecida com 6 algoritmos de hash diferentes:

  • MD5: 16 bytes (tempo para o hash 500MB: 1462 ms)
  • SHA-1: 20 bytes (1644 ms)
  • SHA256: 32 bytes (5618 ms)
  • SHA384: 48 bytes (3839 ms)
  • SHA512: 64 bytes (3820 ms)
  • RIPEMD: 20 bytes (7066 ms)

Cada uma dessas funções executa de maneira diferente; MD5 sendo o mais rápido e RIPEMD sendo o mais lento.

O MD5 tem a vantagem de se encaixar no tipo Guid incorporado; e é a base do tipo 3 UUID . O hash SHA-1 é a base do UUID do tipo 5. O que os torna realmente fáceis de usar para identificação.

No entanto, o MD5 é vulnerável a ataques de colisão , o SHA-1 também é vulnerável, mas em menor grau.

Sob quais condições devo usar qual algoritmo de hash?

Perguntas particulares que estou realmente curioso para ver respondidas são:

  • MD5 não é confiável? Em situações normais, quando você usa o algoritmo MD5 sem intenção maliciosa e nenhum terceiro tem intenção maliciosa, você esperaria QUALQUER colisão (ou seja, dois bytes arbitrários [] produzindo o mesmo hash)

  • Quanto melhor o RIPEMD do que o SHA1? (se melhor) é 5 vezes mais lento para calcular, mas o tamanho do hash é o mesmo que o SHA1.

  • Quais são as chances de obter colisões não-maliciosas ao misturar nomes de arquivos (ou outras seqüências curtas)? (Por exemplo, 2 nomes de arquivos aleatórios com o mesmo hash MD5) (com MD5 / SHA1 / SHA2xx) Em geral, quais são as chances de colisões não maliciosas?

Esta é a referência que eu usei:

    static void TimeAction(string description, int iterations, Action func) {
        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < iterations; i++) {
            func();
        }
        watch.Stop();
        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
    }

    static byte[] GetRandomBytes(int count) {
        var bytes = new byte[count];
        (new Random()).NextBytes(bytes);
        return bytes;
    }


    static void Main(string[] args) {

        var md5 = new MD5CryptoServiceProvider();
        var sha1 = new SHA1CryptoServiceProvider();
        var sha256 = new SHA256CryptoServiceProvider();
        var sha384 = new SHA384CryptoServiceProvider();
        var sha512 = new SHA512CryptoServiceProvider();
        var ripemd160 = new RIPEMD160Managed();

        var source = GetRandomBytes(1000 * 1024);

        var algorithms = new Dictionary<string,HashAlgorithm>();
        algorithms["md5"] = md5;
        algorithms["sha1"] = sha1;
        algorithms["sha256"] = sha256;
        algorithms["sha384"] = sha384;
        algorithms["sha512"] = sha512;
        algorithms["ripemd160"] = ripemd160;

        foreach (var pair in algorithms) {
            Console.WriteLine("Hash Length for {0} is {1}", 
                pair.Key, 
                pair.Value.ComputeHash(source).Length);
        }

        foreach (var pair in algorithms) {
            TimeAction(pair.Key + " calculation", 500, () =>
            {
                pair.Value.ComputeHash(source);
            });
        }

        Console.ReadKey();
    }
Sam Saffron
fonte
15
O fato de você mencionar o md5 se encaixa no formato GUID (16 bytes) sugere um mal-entendido fundamental. Não é garantido que um hash seja exclusivo, mas é raro (e difícil de falsificar se usado em um sentido criptográfico) e deriva do que é um hash, enquanto um GUID é, bem, único, mas não relacionado ao conteúdo do coisa que identifica. Eles são usados ​​para fins muito diferentes.
Barry Wark
1
Corrija o que não está relacionado, é apenas um fato específico da implementação útil. Entendo que você não pode ajustar o infinito em 16 bytes. Você pode obter colisões com qualquer algoritmo de hash
Sam Saffron
5
Além disso, um Guid é apenas único na prática, em teoria, se você continuasse gerando Guids, eventualmente obteria duplicatas.
Sam Saffron
3
Você realmente não deve inserir um hash em um GUID, mesmo que seja adequado. Exemplo mais simples: duas cópias do mesmo arquivo devem ter GUIDs diferentes, mas o mesmo hash. As primeiras 8 letras do nome de uma pessoa também se encaixam perfeitamente em 16 bytes.
dbkk
2
@ user2332868 A quebra do SHA-1 não afeta a probabilidade de colisões acidentais . Quando uma intenção maliciosa é uma ameaça para o seu uso, acho que escolher cegamente qualquer função de hash está errado e você precisa gastar tempo fazendo análises de risco / custo para o seu caso específico.
Andrey Tarantsov 03/04

Respostas:

138

Na criptografia, as funções de hash fornecem três funções separadas.

  1. Resistência à colisão : quão difícil é para alguém encontrar duas mensagens ( quaisquer duas mensagens) com o mesmo hash.
  2. Resistência à pré-imagem : Dado um hash, quão difícil é encontrar outra mensagem com o mesmo hash? Também conhecida como função de hash unidirecional .
  3. Resistência à segunda pré-imagem : dada uma mensagem, encontre outra mensagem que tenha o mesmo hash.

Essas propriedades estão relacionadas, mas independentes. Por exemplo, a resistência à colisão implica uma segunda resistência à pré-imagem, mas não o contrário. Para qualquer aplicativo, você terá requisitos diferentes, necessitando de uma ou mais dessas propriedades. Uma função de hash para proteger senhas em um servidor geralmente requer apenas resistência à pré-imagem, enquanto os resumos de mensagens exigem todos os três.

Foi demonstrado que o MD5 não é resistente a colisões, no entanto, isso não impede seu uso em aplicações que não exigem resistência a colisões. De fato, o MD5 ainda é freqüentemente usado em aplicações em que o tamanho e a velocidade da chave menores são benéficos. Dito isto, devido a suas falhas, os pesquisadores recomendam o uso de outras funções de hash em novos cenários.

O SHA1 possui uma falha que permite encontrar colisões em teoricamente muito menor do que as 2 ^ 80 etapas que uma função segura de hash de seu comprimento exigiria. O ataque está sendo revisado continuamente e atualmente pode ser feito em ~ 2 ^ 63 etapas - apenas dentro do domínio atual da computabilidade. Por esse motivo, o NIST está eliminando progressivamente o uso do SHA1, declarando que a família SHA2 deve ser usada após 2010.

SHA2 é uma nova família de funções de hash criadas após o SHA1. Atualmente, não há ataques conhecidos contra funções SHA2. SHA256, 384 e 512 fazem parte da família SHA2, apenas usando comprimentos de chave diferentes.

RIPEMD Não posso comentar muito, exceto notar que não é tão comumente usado como as famílias SHA e, portanto, não foi analisado tão minuciosamente pelos pesquisadores criptográficos. Por esse motivo, eu recomendaria o uso de funções SHA sobre ele. Na implementação que você está usando, parece bastante lento também, o que a torna menos útil.

Em conclusão, não existe uma melhor função - tudo depende do que você precisa. Lembre-se das falhas de cada uma delas e você poderá escolher a função de hash certa para o seu cenário.

Eric Burnett
fonte
1
Realmente aprecio você entrar neste nível de detalhe. Isso é muito útil.
Joelc
1
Para algumas aplicações, mesmo uma função de hash sem grau criptográfico pode ser apropriada. O OP nunca mencionou se era especificamente para senhas, autenticação de resposta a desafio, tokens de acesso ou apenas para indexar um monte de strings / arquivos. Desempenho, por outro lado, é uma preocupação para o OP ...
Seva Alekseyev
111

Todas as funções de hash estão "quebradas"

O princípio do buraco de pombo diz que, por mais que você tente, você não pode colocar mais de 2 pombos em 2 furos (a menos que você os corte). Da mesma forma, você não pode ajustar 2 ^ 128 + 1 números em 2 ^ 128 slots. Todas as funções de hash resultam em um hash de tamanho finito, isso significa que você sempre pode encontrar uma colisão se pesquisar nas seqüências "tamanho finito" + 1. Simplesmente não é viável fazê-lo. Não para o MD5 e não para o Skein .

MD5 / SHA1 / Sha2xx não têm chances de colisão

Todas as funções de hash têm colisões, é um fato da vida. Encontrar essas colisões por acidente é o equivalente a ganhar na loteria intergaláctica . Ou seja, ninguém ganha na loteria intergaláctica , simplesmente não é assim que a loteria funciona. Você nunca encontrará um hash MD5 / SHA1 / SHA2XXX acidental, NUNCA. Todas as palavras em todos os dicionários, em todos os idiomas, têm um valor diferente. Todo nome de caminho, em todas as máquinas do planeta inteiro, possui um hash MD5 / SHA1 / SHA2XXX diferente. Como eu sei disso, você pode perguntar. Bem, como eu disse antes, ninguém ganha na loteria intergaláctica, nunca.

Mas ... MD5 está quebrado

Às vezes, o fato de estar quebrado não importa .

Atualmente, não existem ataques de pré-imagem ou segunda pré-imagem conhecidos no MD5.

Então, o que há de tão errado no MD5, você pode perguntar? É possível que terceiros gerem 2 mensagens, uma das quais é EVIL e outra é BOA, ambas com o mesmo valor. ( Ataque de colisão )

No entanto, a recomendação atual da RSA não é usar o MD5 se você precisar de resistência à pré-imagem. As pessoas tendem a agir com cautela quando se trata de algoritmos de segurança.

Então, qual função de hash devo usar no .NET?

  • Use o MD5 se precisar da velocidade / tamanho e não se importa com ataques de aniversário ou ataques de pré-imagem.

Repita isso comigo, não há chance de colisões MD5 , colisões maliciosas podem ser cuidadosamente projetadas. Mesmo que não existam ataques de pré-imagem conhecidos até o momento no MD5, a linha dos especialistas em segurança é que o MD5 não deve ser usado onde você precisa se defender contra ataques de pré-imagem. O mesmo vale para SHA1 .

Lembre-se de que nem todos os algoritmos precisam se defender contra ataques de pré-imagem ou colisão. Veja o caso trivial de uma pesquisa de primeira passagem por arquivos duplicados no seu HD.

  • Use a função baseada em SHA2XX se desejar uma função de hash criptograficamente segura.

Ninguém nunca encontrou colisão com o SHA512. SEMPRE. Eles tentaram muito. Aliás, ninguém jamais encontrou colisão SHA256 ou 384. .

  • Não use SHA1 ou RIPEMD, a menos que seja para um cenário de interoperabilidade.

RIPMED não recebeu a mesma quantidade de escrutínio que SHAX e MD5 receberam. O SHA1 e o RIPEMD são vulneráveis ​​a ataques de aniversário. Ambos são mais lentos que o MD5 no .NET e têm um tamanho estranho de 20 bytes. É inútil usar essas funções, esquecê-las.

Os ataques de colisão do SHA1 estão reduzidos a 2 ^ 52, não vai demorar muito até que as colisões do SHA1 ocorram em estado selvagem.

Para obter informações atualizadas sobre as várias funções de hash, consulte o zoo da função de hash .

Mas espere, há mais

Ter uma função rápida de hash pode ser uma maldição. Por exemplo: um uso muito comum para funções de hash é o armazenamento de senhas. Essencialmente, você calcula o hash de uma senha combinada com uma sequência aleatória conhecida (para impedir ataques do arco-íris) e armazena esse hash no banco de dados.

O problema é que, se um invasor receber um despejo do banco de dados, ele poderá adivinhar com eficiência as senhas usando força bruta. Cada combinação que ele tenta leva apenas uma fração de milissegundo e ele pode experimentar centenas de milhares de senhas por segundo.

Para contornar esse problema, o algoritmo bcrypt pode ser usado, ele foi projetado para ser lento, para que o invasor fique muito mais lento se estiver atacando um sistema usando o bcrypt. Recentemente, o scrypt ganhou destaque e é considerado por alguns como mais eficaz que o bcrypt, mas eu não conheço uma implementação .Net.

Sam Saffron
fonte
Enquanto o MD5 e o SHA-1 foram enfraquecidos, o MD5 é muito mais fraco que o SHA-1, embora apenas um pouco mais rápido. As colisões MD5 reais foram encontradas e usadas para explorações do mundo real (forjando certificados de CA), mas até onde eu sei, nenhuma colisão SHA-1 real foi encontrada (embora o número de operações tenha sido consideravelmente reduzido a partir da força bruta). E dado o MD5 mais fraco, não ficaria surpreso se os ataques de segunda pré-imagem aparecessem mais cedo no MD5 do que no SHA-1. Portanto, acho que você deve usar o SHA-1 se precisar de velocidade e não de resistência à colisão e, caso contrário, use um da família SHA-2.
Brian Campbell
1
@Brian é bastante claro que nos próximos anos as pessoas poderão executar ataques de colisão no SHA1, isso efetivamente tornará o SHA1 tão útil quanto o MD5. O certificado da CA é um ataque de colisão, da mesma forma que em poucos anos as pessoas poderão para executar o mesmo ataque nos certificados de CA SHA1. O ataque depende de uma parte maliciosa que cria um certificado EVIL e GOOD. Não há ataques de pré-imagem conhecidos no MD5 e o fato de haver ataques de colisão não torna os ataques de pré-imagem mais ou menos prováveis.
Sam Saffron
É muito menos sobre qual hash você usa para senhas, do que é o que é hash. Se seu salt é conhecido, seu banco de dados fica imediatamente vulnerável a um ataque de dicionário; se seu salt for processual e seu sistema de arquivos estiver comprometido, você estará (novamente) vulnerável; se seu sal for omitido, você estará novamente comprometido. A segurança em questão é, não importa o que seja, o que é hash. Certificados, não irei abordar porque não os tratei como programador (IE, criação, entendimento, etc.).
Robert K
O termo quebrado tem um significado específico no contexto de hash, e não é o significado que essa resposta enfatiza. Tudo o que essa resposta fará é causar confusão.
Joel McBeth #
1
Essa é uma excelente resposta, pois se concentra na praticidade. Hashes são usados ​​para outras coisas que não a segurança (como gerar chaves de pesquisa de cache para dados não sensíveis ou determinar se um objeto serializado foi alterado). As chances de um ataque direcionado são praticamente nulas (nunca diga nunca) e, mesmo que um ataque tenha sucesso, ele não terá impacto material. Excelente trabalho focado no impacto prático (em vez de teórico).
DVK
35

Atualizar:

Os tempos mudaram, temos um vencedor do SHA3. Eu recomendaria o uso do vencedor do concurso SHA3, keccak (aka SHA3 ).

Resposta original:

Em ordem do mais fraco ao mais forte, eu diria:

  1. RIPEMD BROKEN, nunca deve ser usado como pode ser visto neste pdf
  2. MD-5 BROKEN, nunca deve ser usado, pode ser quebrado em 2 minutos com um laptop
  3. SHA-1 QUEBRADO, nunca deve ser usado, está quebrado, os ataques estão melhorando a cada semana
  4. SHA-2 FRACO, provavelmente será quebrado nos próximos anos. Algumas fraquezas foram encontradas. Observe que, geralmente, quanto maior o tamanho da chave, mais difícil é a quebra da função hash. Enquanto tamanho da chave = força nem sempre é verdadeiro, é principalmente verdade. Portanto, o SHA-256 é provavelmente mais fraco que o SHA-512.
  5. Skein NENHUMA fraqueza conhecida, é candidata ao SHA-3 . É relativamente novo e, portanto, não testado. Foi implementado em vários idiomas.
  6. MD6 NENHUM FRAQUEZ CONHECIDO, é outro candidato ao SHA-3. Provavelmente mais forte que Skien, mas mais lento em máquinas de núcleo único. Como Skien, não é testado. Alguns desenvolvedores preocupados com segurança o estão usando, em funções de missão crítica .

Pessoalmente, eu usaria o MD6, porque nunca se pode ser muito paranóico. Se a velocidade é uma preocupação real, eu consideraria o Skein, ou o SHA-256.

Ethan Heilman
fonte
5
Eu não colocaria Skein e MD6 tão alto na lista; existe uma razão para que a competição SHA-3 não termine até o final de 2012. Demora muito tempo e muitos olhos para se convencer de que uma função de hash provavelmente é segura e nenhuma dessas funções já existem há tempo suficiente para isso.
Eric Burnett
Concordo com seus sentimentos, mas acho que a comunidade está em uma posição estranha. Todas as funções de hash em uso estão perigosamente próximas de serem quebradas (talvez, talvez, não o SHA2 256-512) e, no entanto, precisamos esperar até 2012 para escolher um substituto. escolha seu veneno: fraco / quebrado ou não testado (a maioria dos candidatos ao NIST não é pública há mais de 6 meses)? Escolha difícil.
Ethan Heilman
5
O RIPEMD está quebrado, mas o RIPEMD-128/160/256 é diferente e não está quebrado.
Bwooce 27/02
Não conheço nenhuma implementação de desempenho do Skein for .NET. Eu me deparei com SkeinFish e nskein, e ambos eram muito lentos.
Cocowalla
1
Eu esperaria com o uso do SHA-3 até que o padrão real esteja disponível, pelo menos se você quiser realmente seguir um padrão. O algoritmo em si tem muitas opções.
Paŭlo Ebermann
3

Na defesa do MD5, não há maneira conhecida de produzir um arquivo com um hash MD5 arbitrário. O autor original deve planejar com antecedência para ter uma colisão de trabalho. Portanto, se o receptor confia no remetente, o MD5 está bem. O MD5 é quebrado se o assinante for malicioso, mas não se sabe que ele é vulnerável a ataques intermediários.

rlbond
fonte
1
Embora eu não seja um especialista nesse campo, não é quase possível calcular hashes MD5 arbitrários pela força bruta hoje em dia?
Mafu
@mafu: Resposta tardia aqui, mas é possível calcular qualquer hash via força bruta. Isso pode levar muito tempo.
Warty
@ItzWarty Eu estava me referindo especificamente ao tempo necessário - já que o MD5 é bastante curto, achei que seria possível simplesmente lançar uma fonte de computação razoável nele (E3, ou uma grade de computadores barata para algumas máquinas com algumas placas gráficas, algo nesse sentido) e poder calcular um hash MD5 arbitrário dentro de, digamos, alguns dias.
mafu
@mafu Um ataque de pré-imagem custa 2 ^ 127 invocações de hash para um hash de 128 bits. Isso está longe de ser viável. As invocações 2 ^ 80 são possíveis, mas já muito caras.
CodesInChaos 14/03
2

Qual deles você realmente usa depende do que está usando. Se você quiser apenas garantir que os arquivos não sejam corrompidos durante o transporte e não se preocupe com a segurança, vá rápido e pequeno. Se você precisar de assinaturas digitais para acordos de resgate federal de vários bilhões de dólares e precisar se certificar de que não são forjados, faça um trabalho de falsificação e lentidão.

tvanfosson
fonte
1
Muitas vezes, ao discutir soluções para o problema, mencionei que eu uso o MD5 para identidade rápida (hash uma string), eles dizem "mas o md5 está quebrado ... não use, use sha1" ... Eu realmente não assinei isso, estava pensando se alguma coisa está tão fundamentalmente quebrado com alguns dos hashs mais fracos que devem ser evitados ... por exemplo, casos verdadeiras obras onde os dados normais produz colisões
Sam Saffron
Vendo que o MD5 funcionou bem para milhões de pessoas durante quinze anos, suspeito que não há problema em você se a segurança de hash não for crucial.
Mqp 29/04/09
2
O @sambo MD5 funciona bem em quase todos os casos, exceto quando a segurança / integridade real do seu sistema depende da prevenção de colisões.
Rex M
2

Eu gostaria de enfatizar (antes que o md5 seja dividido) que eu ainda uso o md5 extensivamente, apesar de sua avaria esmagadora para muitas criptomoedas.

Contanto que você não se importe em proteger contra colisões (você ainda pode usar o md5 em um hmac) e deseja a velocidade (às vezes deseja um hash mais lento), ainda poderá usar o md5 com confiança.

Mike Boers
fonte
@ Mike, estou com você nisso, era o tipo de coisa que eu estava procurando com esta pergunta, é algo sobre as funções mais fracas de hash tão fundamentalmente quebradas que elas nunca devem ser usadas.
Sam Saffron
Além disso, se os dados ou a segurança exigida tiverem uma vida útil mais curta que o período de crack (alguns minutos hoje em dia), o MD5 está absolutamente bom. Situacionalmente útil, mas ainda útil, é o ponto.
Annakata
@annakata - Lembre-se de que você também deve evitar a reutilização de chaves em várias mensagens para que seja utilizável nessas circunstâncias.
9788 Steve Jobs
2

Seria uma boa idéia dar uma olhada no algoritmo BLAKE2.

Como é descrito, é mais rápido que o MD5 e pelo menos tão seguro quanto o SHA-3. Também é implementado por vários aplicativos de software , incluindo o WinRar.

Florin Mircea
fonte
Pode ser mais rápido, exceto que muitas implementações têm suporte de hardware, o que torna o SHA-256 bastante rápido.
Zaph 22/08/16
Concordo. a partir de 2019, o Blake2b é o melhor hash de uso geral lançado até o momento. Significativamente mais rápido que todas as outras alternativas, e não menos seguro (pelo menos de maneira significativa) e pode ser executado em apenas 336 bytes de ram (168 para blake2s), oh, e é otimizado para CPUs little-endian, o que é o endian dominante nos sistemas de hoje.
hanshenrik
0

Não sou especialista nesse tipo de coisa, mas acompanho a comunidade de segurança e muitas pessoas consideram o hash MD5 quebrado. Eu diria que qual usar depende da sensibilidade dos dados e da aplicação específica. Você pode se safar com um hash um pouco menos seguro, desde que a chave seja boa e forte.

blueintegral
fonte
1
funções hash normalmente não usar chaves
Ethan Heilman
0

Aqui estão as minhas sugestões para você:

  1. Você provavelmente deve esquecer o MD5 se antecipar ataques. Existem muitas tabelas arco-íris para elas on-line, e sabe-se que empresas como a RIAA são capazes de produzir sequências com hashes equivalentes.
  2. Use sal, se puder. A inclusão do tamanho da mensagem na mensagem pode dificultar muito a colisão de hash útil.
  3. Como regra geral, mais bits significa menos colisões (pelo princípio do buraco de fechadura) e mais lento e talvez mais seguro (a menos que você seja um gênio da matemática que possa encontrar vulnerabilidades).

Veja aqui um artigo detalhando um algoritmo para criar colisões md5 em 31 segundos com um computador Intel P4 de mesa.

http://eprint.iacr.org/2006/105

Desconhecido
fonte
Esse comentário é muito antigo e parece bastante enterrado, mas esse trecho - sabe-se que o RIAA é capaz de produzir sequências com hashes equivalentes - me ocorreu, e estou muito curioso sobre o contexto para isso. Em particular, a brutalidade do MD5 há 8 anos era um pouco menos trivial do que em 2017, então eles devem ter um bom motivo.
I336_ 13/03/19