Por que o Git não usa SHA mais moderno?

90

Eu li sobre que o Git usa o resumo SHA-1 como um ID para uma revisão. Por que não usa uma versão mais moderna do SHA?

qazwsx
fonte
2
Desempenho é a única razão que consigo pensar, o SHA-1 é mais rápido que o SHA-2. Pessoalmente, considero uma má decisão, uma vez que a resistência à colisão do SHA-1 é bastante fraca.
CodesInChaos
4
stackoverflow.com/questions/9392365/… - não é uma correspondência exata, mas cobre terreno semelhante
softwariness
6
Isso foi discutido na lista de e-mails do git em 2006. Veja o tópico completo . Para resumir, Linus disse na época que o SHA-1 só precisava ser único o suficiente para que as colisões não ocorressem, o que é verdade. SHA-1 não é um recurso de segurança do git. "Qualquer pessoa que aceite cegamente dados de fontes não confiáveis ​​está ferrada de tantas outras maneiras que o ataque hash simplesmente nem está no radar." - Linus
tbc0
28
Atualização: colisões SHA-1 agora na selva shattered.it
desenhou em
2
Primeiro trimestre de 2018: este esforço para apoiar um SHA alternativo está em andamento: veja minha resposta abaixo
VonC

Respostas:

62

Por que não usa uma versão mais moderna do SHA?

Dezembro de 2017: Vai. E o Git 2.16 (primeiro trimestre de 2018) é o primeiro lançamento para ilustrar e implementar essa intenção.

Nota: veja Git 2.19 abaixo: será SHA-256 .

O Git 2.16 irá propor uma infraestrutura para definir qual função hash é usada no Git e iniciará um esforço para sondar isso em vários codepaths.

Consulte commit c250e02 (28 de novembro de 2017) por Ramsay Jones (``) .
Consulte commit eb0ccfd , commit 78a6766 , commit f50e766 , commit abade65 (12 nov 2017) por brian m. Carlson ( bk2204) .
(Fundido por Junio ​​C Hamano - gitster- no commit 721cc43 , 13 de dezembro de 2017)


Adicionar estrutura que representa o algoritmo hash

Como no futuro queremos oferecer suporte a um algoritmo hash adicional, adicione uma estrutura que represente um algoritmo hash e todos os dados que devem acompanhá-lo .
Adicione uma constante para permitir a enumeração fácil de algoritmos de hash .
Implemente a funçãotypedefs para criar uma API abstrata que pode ser usada por qualquer algoritmo hash e wrappers para as funções SHA1 existentes que estão em conformidade com esta API.

Exponha um valor para o tamanho hexadecimal, bem como para o tamanho binário .
Embora um seja sempre o dobro do outro, os dois valores são usados ​​de forma extremamente comum em toda a base de código e fornecer ambos leva a uma legibilidade aprimorada.

Não inclua uma entrada na estrutura do algoritmo hash para o ID de objeto nulo.
Como esse valor é composto apenas por zeros, qualquer ID de objeto totalmente zero de tamanho adequado pode ser usado e não há necessidade de armazenar um determinado por hash.

O plano de transição da função hash atual prevê um momento em que aceitaremos a entrada do usuário que pode estar em SHA-1 ou no formato NewHash.
Como não podemos saber qual foi o usuário fornecido, adicione uma constante representando o algoritmo desconhecido para nos permitir indicar que devemos procurar o valor correto.


Integre o suporte ao algoritmo hash com a configuração do repo

Em versões futuras do Git, planejamos oferecer suporte a um algoritmo hash adicional.
Integre a enumeração de algoritmos de hash com a configuração do repositório e armazene um ponteiro para os dados enumerados no repositório de struct .
Claro, atualmente só oferecemos suporte a SHA-1, portanto, codifique esse valor em read_repository_format .
No futuro, vamos enumerar esse valor da configuração.

Adicione uma constante,,the_hash_algo que aponta para o hash_algoponteiro da estrutura no repositório global.
Observe que este é o hash que é usado para serializar dados no disco, não o hash que é usado para exibir itens para o usuário.
O plano de transição prevê que eles possam ser diferentes.
Podemos adicionar um elemento adicional no futuro (digamos, ui_hash_algo) para fornecer para este caso.


Atualização de agosto de 2018, para Git 2.19 (terceiro trimestre de 2018), Git parece escolher SHA-256 como NewHash.

Veja o commit 0ed8d8d (04 de agosto de 2018) de Jonathan Nieder ( artagnon) .
Veja o commit 13f5e09 (25 de julho de 2018) de Ævar Arnfjörð Bjarmason ( avar) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 34f2297 , 20 de agosto de 2018)

dochash-function-transition : escolha SHA-256 como NewHash

Do ponto de vista da segurança, parece que SHA-256, BLAKE2, SHA3-256, K12 e assim por diante têm propriedades de segurança semelhantes.
Todas são boas opções do ponto de vista da segurança.

SHA-256 tem uma série de vantagens:

  • Já existe há algum tempo, é amplamente usado e é suportado por quase todas as bibliotecas de criptografia (OpenSSL, mbedTLS, CryptoNG, SecureTransport, etc).

  • Quando você compara com o SHA1DC, a maioria das implementações vetorizadas do SHA-256 são realmente mais rápidas, mesmo sem aceleração.

  • Se estivermos fazendo assinaturas com OpenPGP (ou mesmo, suponho, CMS), vamos usar SHA-2, então não faz sentido ter nossa segurança dependente de dois algoritmos separados quando um deles sozinho poderia quebrar a segurança quando podíamos apenas depender de um.

Então é SHA-256 .
Atualize o documento de design da transição da função hash para dizer isso.

Após este patch, não há instâncias restantes da string " NewHash", exceto para um uso não relacionado de 2008 como um nome de variável em t/t9700/test.pl .


Você pode ver esta transição para SHA 256 em andamento com Git 2.20 (quarto trimestre de 2018):

Ver cometer 0d7c419 , cometer dda6346 , cometer eccb5a5 , cometer 93eb00f , cometer d8a3a69 , cometer fbd0e37 , cometer f690b6b , cometer 49d1660 , cometer 268babd , cometer fa13080 , cometer 7b5e614 , cometer 58ce21b , cometer 2f0c9e9 , cometer 825544a (15 out 2018) por Brian M . Carlson ( bk2204) .
Ver commit 6afedba (15 out 2018) de SZEDER Gábor ( szeder) .
(Fundido porJunio ​​C Hamano - gitster- no commit d829d49 , 30 de outubro de 2018)

substitua constantes codificadas

Substitua várias constantes baseadas em 40 por referências a GIT_MAX_HEXSZou the_hash_algo, conforme apropriado.
Converta todos os usos do GIT_SHA1_HEXSZpara usar de the_hash_algomodo que sejam apropriados para qualquer comprimento de hash dado.
Em vez de usar uma constante codificada para o tamanho de um ID de objeto hexadecimal, mude para usar o ponteiro calculado a partir parse_oid_hexdesses pontos após o ID de objeto analisado.

GIT_SHA1_HEXSZé posteriormente removido / substituído pelo Git 2.22 (Q2 2019) e commit d4e568b .


Essa transição continua com o Git 2.21 (primeiro trimestre de 2019), que adiciona o hash sha-256 e o ​​conecta por meio do código para permitir a construção do Git com o "NewHash".

Ver cometer 4b4e291 , cometer 27dc04c , cometer 13eeedb , cometer c166599 , cometer 37649b7 , cometer a2ce0a7 , cometer 50c817e , cometer 9a3a0ff , cometer 0dab712 , cometer 47edb64 (14 novembro de 2018), e cometer 2f90b9d , cometer 1ccf07c (22 de outubro de 2018) por Brian M . Carlson ( bk2204) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 33e4ae9 , 29 de janeiro de 2019)

Adicionar uma implementação básica de suporte SHA-256 (fevereiro de 2019)

SHA-1 é fraco e precisamos fazer a transição para uma nova função hash.
Por algum tempo, nos referimos a essa nova função como NewHash.
Recentemente, decidimos escolher SHA-256 comoNewHash .
As razões por trás da escolha do SHA-256 são descritas neste tópico e no histórico de commits para o documento de transição da função hash.

Adicione uma implementação básica baseada em SHA-256 libtomcrypt, que é de domínio público.
Otimize-o e reestruture-o para atender aos nossos padrões de codificação.
Puxe as funções de atualização e final da implementação do bloco SHA-1, pois sabemos que elas funcionam corretamente com todos os compiladores. Esta implementação é mais lenta que SHA-1, mas mais implementações de desempenho serão introduzidas em commits futuros.

Conecte o SHA-256 à lista de algoritmos de hash e adicione um teste de que o algoritmo funciona corretamente.

Observe que com este patch, ainda não é possível mudar para o uso de SHA-256 no Git.
Patches adicionais são necessários para preparar o código para lidar com um algoritmo hash maior e outras correções de teste são necessárias.

hash: adicione uma implementação SHA-256 usando OpenSSL

Já temos rotinas OpenSSL disponíveis para SHA-1, então adicione rotinas para SHA-256 também.

Em um Core i7-6600U, esta implementação SHA-256 se compara favoravelmente à implementação SHA1DC SHA-1:

SHA-1: 157 MiB/s (64 byte chunks); 337 MiB/s (16 KiB chunks)
SHA-256: 165 MiB/s (64 byte chunks); 408 MiB/s (16 KiB chunks)

sha256: adicione uma implementação SHA-256 usando libgcrypt

Geralmente, obtém-se melhor desempenho de rotinas criptográficas escritas em assembly do que C, e isso também é verdadeiro para SHA-256.
Além disso, a maioria das distribuições Linux não pode distribuir Git vinculado ao OpenSSL por motivos de licenciamento.

A maioria dos sistemas com GnuPG também terá libgcrypt, uma vez que é uma dependência do GnuPG.
libgcrypttambém é mais rápido do que a implementação SHA1DC para mensagens de alguns KiB e maiores.

Para comparação, em um Core i7-6600U, esta implementação processa pedaços de 16 KiB a 355 MiB / s, enquanto o SHA1DC processa pedaços equivalentes a 337 MiB / s.

Além disso, libgcrypt é licenciado sob a LGPL 2.1, que é compatível com a GPL. Adicione uma implementação de SHA-256 que usa libgcrypt.


O esforço de atualização continua com o Git 2.24 (quarto trimestre de 2019)

Veja commit aaa95df , commit be8e172 , commit 3f34d70 , commit fc06be3 , commit 69fa337 , commit 3a4d7aa , commit e0cb7cd , commit 8d4d86b , cometer f6ca67d , cometer dd336a5 , cometer 894c0f6 , cometer 4439c7a , cometer 95518fa , cometer e84f357 , cometer fe9fec4 , cometer 976ff7e , cometer 703d2d4 , cometer 9d958cc , cometer 7962e04 , cometer taxa 4930(18 de agosto de 2019) por brian m. Carlson ( bk2204) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 676278f , 11 de outubro de 2019)

Em vez de usar GIT_SHA1_HEXSZe constantes codificadas, mude para usar the_hash_algo.


Com o Git 2.26 (Q1 2020), os scripts de teste estão prontos para o dia em que os nomes dos objetos usarão SHA-256.

Ver commit 277eb5a , commit 44b6c05 , commit 7a868c5 , commit 1b8f39f , commit a8c17e3 , commit 8320722 , commit 74ad99b , commit ba1be1a , commit cba472d , commit 82d5aeb , commit 3c5e65c , cometer 235d3cd , cometer 1d86c8f , cometer 525a7f1 , cometer 7a1bcb2 , cometer cb78f4f , cometer 717c939 , commit 08a9dd8 , commit 215b60b , commit 194264c(21 de dezembro de 2019) por brian m. Carlson ( bk2204) .
(Fundido por Junio ​​C Hamano - gitster- no commit f52ab33 , 05 de fevereiro de 2020)

Exemplo:

t4204: torna o tamanho do hash independente

Assinado por: brian m. Carlson

Use em $OID_REGEXvez de uma expressão regular codificada.

Então, em vez de usar:

grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output

Os testes estão usando

grep "^$OID_REGEX $(git rev-parse HEAD)$" output

E OID_REGEXvem de commit bdee9cd (13 de maio de 2018) por brian m. Carlson ( bk2204) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 9472b13 , 30 de maio de 2018, Git v2.18.0-rc0)

t/test-lib: introduzir OID_REGEX

Assinado por: brian m. Carlson

Atualmente temos uma variável, $_x40,que contém uma regex que corresponde a uma constante hexadecimal completa de 40 caracteres.

No entanto, com NewHash, teremos IDs de objeto com mais de 40 caracteres.

Nesse caso, $_x40será um nome confuso.

Crie um $OID_REGEX variável que sempre refletirá uma regex correspondente ao ID de objeto apropriado, independentemente do comprimento do hash atual.

E, ainda para testes:

Ver commit f303765 , commit edf0424 , commit 5db24dc , commit d341e08 , commit 88ed241 , commit 48c10cc , commit f7ae8e6 , commit e70649b , commit a30f93b , commit a79eec2 , commit 796d138 , commit 417e45e , brian m. Carlson ( cometer dfa5f53 , cometer f743e8f , cometer 72f936b , cometer 5df0f11 , cometer 07877f3 , commit 6025e89 , commit 7b1a182 , commit 94db7e3 ,commit db12505 (07 Fev 2020) porbk2204 ) .
(Fundido por Junio ​​C Hamano - gitster- no commit 5af345a , 17 de fevereiro de 2020)

t5703: faça o teste funcionar com SHA-256

Assinado por: brian m. Carlson

Este teste usou um ID de objeto com 40 caracteres hexadecimais de comprimento, fazendo com que o teste não apenas não passasse, mas travasse, quando executado com SHA-256 como hash.

Altere este valor para um ID de objeto fictício fixo usando test_oid_initetest_oid .

Além disso, certifique-se de extrair um ID de objeto do comprimento apropriado usando corte com campos em vez de um comprimento fixo.


Alguns codepaths receberam uma instância de repositório como parâmetro para trabalhar no repositório, mas passaram the_repository instância para seus callees, que foram limpos (um pouco) com Git 2.26 (Q1 2020).

Veja commit b98d188 , commit 2dcde20 , commit 7ad5c44 , commit c8123e7 , commit 5ec9b8a , commit a651946 , commit eb999b3 (30 Jan 2020) por Matheus Tavares ( matheustavares) .
(Fundido por Junio ​​C Hamano - gitster- no commit 78e67cd , 14 de fevereiro de 2020)

sha1-file: permite check_object_signature()lidar com qualquer repo

Assinado por: Matheus Tavares

Alguns chamadores de check_object_signature()podem trabalhar em repositórios arbitrários, mas o repo não é passado para esta função. Em vez disso, the_repositoryé sempre usado internamente.
Para corrigir possíveis inconsistências, permita que a função receba um repositório de struct e faça com que esses chamadores repassem o repo que está sendo tratado.

Baseado em:

sha1-file: passe git_hash_algoparahash_object_file()

Assinado por: Matheus Tavares

Permitir hash_object_file()trabalhar em repositórios arbitrários, introduzindo um git_hash_algoparâmetro. Altere os chamadores que têm um ponteiro de repositório de struct em seu escopo para passar git_hash_algoadiante do referido repo.
Para todos os outros chamadores, repasse the_hash_algo, que já estava sendo usado internamente em hash_object_file().
Esta funcionalidade será usada no seguinte patch para check_object_signature()possibilitar o trabalho em repositórios arbitrários (que, por sua vez, serão usados ​​para corrigir uma inconsistência em object.c: parse_object ()).

VonC
fonte
1
Além disso, não se esqueça de que o Git v2.13.0 e posterior subseqüentemente mudou para uma implementação SHA-1 reforçada por padrão, que não é vulnerável ao ataque SHAttered. Consulte stackoverflow.com/a/43355918/6309
VonC de
1: O Google produziu colisão shattered.io em fevereiro de 2017 (custo estimado em $ 110.000) 2: A Nanyang Technological University produziu um colisão sha-mbles.github.io em janeiro de 2019 (custo estimado entre $ 11k - $ 45k) É hora de Git vai passar SHA1
bristweb
@bristweb "É hora do Git superar o SHA1": Eu concordo, e com o Git 2.25 (lançado hoje), essa mudança é uma. git rev-parseagora pode imprimir o hash que será usado: stackoverflow.com/a/58862319/6309 . E a árvore vazia tem um novo id
SHA2
Com essa extensibilidade de algo hash, o CRC32 pode finalmente brilhar novamente.
Walf
52

ATUALIZAÇÃO : a pergunta acima e esta resposta são de 2015. Desde então, o Google anunciou a primeira colisão SHA-1: https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html


Obviamente, só posso especular de fora sobre o motivo pelo qual o Git continua a usar SHA-1, mas esses podem estar entre os motivos:

  1. Git foi criação de Linus Torvald, e Linus aparentemente não quer substituir o SHA-1 por outro algoritmo de hash neste momento.
  2. Ele faz afirmações plausíveis de que ataques baseados em colisão SHA-1 bem-sucedidos contra Git são muito mais difíceis do que realizar as colisões em si, e considerando que SHA-1 é mais fraco do que deveria ser, não completamente quebrado, isso o torna substancialmente longe de um ataque viável pelo menos hoje. Além disso, ele observa que um ataque "bem-sucedido" alcançaria muito pouco se o objeto em colisão chegasse depois do existente, já que o último seria apenas considerado o mesmo que o válido e ignorado (embora outros tenham apontado que o inverso pode ocorrer).
  3. A troca de software consome tempo e está sujeita a erros, especialmente quando há infraestrutura e dados existentes baseados nos protocolos existentes que terão que ser migrados. Mesmo aqueles que produzem produtos de software e hardware em que a segurança criptográfica é o único ponto do sistema ainda estão em processo de migração do SHA-1 e de outros algoritmos fracos. Imagine todos aqueles unsigned char[20]buffers codificados por todo o lugar ;-), é muito mais fácil programar para agilidade criptográfica no início, em vez de adaptá-la mais tarde.
  4. O desempenho do SHA-1 é melhor do que os vários hashes SHA-2 (provavelmente não tanto a ponto de ser um obstáculo agora, mas talvez fosse um obstáculo há 10 anos), e o tamanho de armazenamento do SHA-2 é maior .

Alguns links:

Minha opinião pessoal seria que, embora os ataques práticos provavelmente demorem algum tempo, e mesmo quando eles ocorrerem, as pessoas provavelmente irão inicialmente mitigá-los com outros meios além de alterar o próprio algoritmo de hash, que se você se preocupa com a segurança, estará errando do lado da cautela com suas escolhas de algoritmos e continuamente revisando para cima seus pontos fortes de segurança, porque as capacidades dos invasores também estão indo apenas em uma direção, então não seria sábio tomar o Git como um modelo, especialmente como seu propósito em o uso de SHA-1 não pretende ser uma segurança criptográfica.

softwariness
fonte
7
"Você pode ter pessoas que tentam ser mal-intencionadas. Elas não terão sucesso. N̶o̶b̶o̶d̶y̶ ̶h̶a̶s̶ ̶b̶e̶e̶n̶ ̶a̶b̶l̶e̶ ̶t̶o̶ ̶b̶r̶e̶a̶k̶ ̶S̶H̶A̶-̶1̶, mas o ponto é o recurso de segurança, mesmo que o SHA-1 . É puramente uma verificação de consistência. " -Linus Torvalds
Shakti
9
Os hashes do Git precisam ser seguros para as assinaturas seguras que as pessoas colocam em seu código para verificar qualquer coisa. Essas assinaturas assinam uma enorme árvore desses hashes. Se algum ramo dessa árvore colidir, um código malicioso pode ser inserido enquanto a assinatura passa. Git é usado de forma incrivelmente ampla agora. É necessária uma atualização hash.
fuzzyTew
Duas coisas a serem consideradas à luz de "estilhaçado": 1. Uso de SHA-1. - SHA-1 é usado como uma soma de verificação glorificada para verificar se há corrupção acidental. - SHA-1 é usado como uma função geradora para fornecer um (um pouco pequeno) número hexadecimal útil para designar objetos dentro de seu armazenamento endereçável de conteúdo (isto é: gerador de nome de arquivo glorificado). - São confirmações assinadas que são responsáveis ​​pela segurança (ou seja: assinatura de criptografia de chave pública. NÃO sha-1)
DrYak
2. Viabilidade - depois de muito tempo de GPU, o Google conseguiu gerar um par de séries de blocos. - ambos hash para a mesma soma SHA-1 (essa é a colisão) - eles são completamente ruins (isso vai ser difícil de justificar porque seu commit tem um bloco gigante de lixo binário no meio). - a demonstração quebrada depende de ter uma maneira de apresentar um comportamento diferente, dependendo de qual lixo binário aleatório está presente. Isso é possível com PDF (que tem uma linguagem de script embutida escondida atrás). Isso vai ser muito mais difícil em fonte simples (pense no Concurso C
dissimulado
@DrYak para 2: vamos supor que você esteja rastreando documentos do photoshop com um campo de comentário neles. Ou outros arquivos de mídia com meta tags. Esse é um caso típico no desenvolvimento de jogos. Mas eles normalmente não serão verificados em cada mudança: por que verificar a metatag se a mensagem de confirmação diz "otimizar para tamanho"?
Arne Babenhauserheide
5

Esta é uma discussão sobre a urgência de migrar do SHA1 para o Mercurial, mas se aplica ao Git também: https://www.mercurial-scm.org/wiki/mpm/SHA1

Resumindo: se você não for extremamente diligente hoje, terá vulnerabilidades muito piores do que sha1. Mas, apesar disso, o Mercurial começou há mais de 10 anos para se preparar para migrar para longe do sha1.

o trabalho está em andamento há anos para adaptar as estruturas de dados e protocolos do Mercurial para os sucessores do SHA1. O espaço de armazenamento foi alocado para hashes maiores em nossa estrutura de revlog há mais de 10 anos no Mercurial 0.9 com a introdução do RevlogNG. O formato bundle2 introduzido mais recentemente suporta a troca de diferentes tipos de hash pela rede. As únicas peças restantes são a escolha de uma função de substituição e a escolha de uma estratégia de compatibilidade com versões anteriores.

Se o git não migrar de sha1 antes do Mercurial, você sempre poderá adicionar outro nível de segurança mantendo um espelho local do Mercurial com hg-git .

Arne Babenhauserheide
fonte
3

Agora há um plano de transição para um hash mais forte, então parece que no futuro ele usará um hash mais moderno do que SHA-1. Do plano de transição atual :

Alguns hashes em consideração são SHA-256, SHA-512/256, SHA-256x16, K12 e BLAKE2bp-256

Paul Wagland
fonte