¿Por qué Git no usa SHA más moderno?


91

Leí sobre que Git usa SHA-1 digest como ID para una revisión. ¿Por qué no usa una versión más moderna de SHA?


2
El rendimiento es la única razón por la que puedo pensar, SHA-1 es más rápido que SHA-2. Personalmente lo considero una mala decisión, ya que la resistencia a colisiones de SHA-1 es bastante débil.
CodesInChaos

4
stackoverflow.com/questions/9392365/… - no es una coincidencia exacta, pero cubre un terreno similar
softwariness

6
Esto se discutió en la lista de correo de git en 2006. Vea el hilo completo . Para resumir, Linus dijo en ese entonces que SHA-1 solo necesitaba ser lo suficientemente único para que no ocurrieran colisiones, que es. SHA-1 no es una función de seguridad para git. "Cualquiera que acepte ciegamente datos de fuentes no confiables está jodido de tantas otras formas que el ataque hash simplemente ni siquiera está en el radar". - Linus
tbc0

28
Actualización: colisiones SHA-1 ahora en estado salvaje shattered.it
drewr

2
Q1 2018: este esfuerzo para respaldar un SHA alternativo está en marcha: vea mi respuesta a continuación
VonC

Respuestas:


62

¿Por qué no usa una versión más moderna de SHA?

Diciembre de 2017: lo hará. Y Git 2.16 (Q1 2018) es la primera versión para ilustrar e implementar esa intención.

Nota: consulte Git 2.19 a continuación: será SHA-256 .

Git 2.16 propondrá una infraestructura para definir qué función hash se usa en Git y comenzará un esfuerzo para sondear eso a través de varias rutas de código.

Consulte la confirmación c250e02 (28 de noviembre de 2017) de Ramsay Jones (``) .
Consulte commit eb0ccfd , commit 78a6766 , commit f50e766 , commit abade65 (12 de noviembre de 2017) por brian m. carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 721cc43 , 13 de diciembre de 2017)


Agregar estructura que represente el algoritmo hash

Dado que en el futuro queremos admitir un algoritmo hash adicional, agregue una estructura que represente un algoritmo hash y todos los datos que deben acompañarlo .
Agregue una constante para permitir una fácil enumeración de algoritmos hash .
Implemente la funcióntypedefs para crear una API abstracta que pueda ser utilizada por cualquier algoritmo hash y envoltorios para las funciones SHA1 existentes que se ajusten a esta API.

Exponga un valor para el tamaño hexadecimal y el tamaño binario .
Si bien uno siempre será el doble del otro, los dos valores se usan con mucha frecuencia en toda la base de código y proporcionan ambos resultados para mejorar la legibilidad.

No incluya una entrada en la estructura del algoritmo hash para el ID de objeto nulo.
Como este valor es todo ceros, se puede utilizar cualquier ID de objeto todo cero de tamaño adecuado, y no es necesario almacenar uno determinado por hash.

El plan de transición de la función hash actual prevé un momento en el que aceptaremos la entrada del usuario que podría estar en SHA-1 o en el formato NewHash.
Dado que no podemos saber cuál ha proporcionado el usuario, agregue una constante que represente el algoritmo desconocido para permitirnos indicar que debemos buscar el valor correcto.


Integrar el soporte del algoritmo hash con la configuración del repositorio

En futuras versiones de Git, planeamos admitir un algoritmo hash adicional.
Integre la enumeración de algoritmos hash con la configuración del repositorio y almacene un puntero a los datos enumerados en el repositorio de estructura .
Por supuesto, actualmente solo admitimos SHA-1, así que codifique este valor en read_repository_format .
En el futuro, enumeraremos este valor de la configuración.

Agregue una constante,the_hash_algo que apunta al hash_algopuntero de estructura en el repositorio global.
Tenga en cuenta que este es el hash que se usa para serializar datos en el disco, no el hash que se usa para mostrar elementos al usuario.
El plan de transición anticipa que estos pueden ser diferentes.
Podemos agregar un elemento adicional en el futuro (digamos, ui_hash_algo) para proporcionar este caso.


Actualización de agosto de 2018, para Git 2.19 (Q3 2018), Git parece elegir SHA-256 como NewHash.

Consulte la confirmación 0ed8d8d (4 de agosto de 2018) de Jonathan Nieder ( artagnon) .
Consulte la confirmación 13f5e09 (25 de julio de 2018) de Ævar Arnfjörð Bjarmason ( avar) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 34f2297 , 20 de agosto de 2018)

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

Desde una perspectiva de seguridad, parece que se cree que SHA-256, BLAKE2, SHA3-256, K12, etc. tienen propiedades de seguridad similares.
Todas son buenas opciones desde el punto de vista de la seguridad.

SHA-256 tiene una serie de ventajas:

  • Ha existido por un tiempo, se usa ampliamente y es compatible con casi todas las bibliotecas de cifrado (OpenSSL, mbedTLS, CryptoNG, SecureTransport, etc.).

  • Cuando se compara con SHA1DC, la mayoría de las implementaciones de SHA-256 vectorizadas son de hecho más rápidas, incluso sin aceleración.

  • Si estamos haciendo firmas con OpenPGP (o incluso, supongo, CMS), usaremos SHA-2, por lo que no tiene sentido que nuestra seguridad dependa de dos algoritmos separados cuando cualquiera de ellos solo podría romper la seguridad cuando solo podíamos depender de uno.

Entonces SHA-256 lo es .
Actualice el documento de diseño de transición de función hash para indicarlo.

Después de este parche, no quedan instancias de la cadena " NewHash", excepto por un uso no relacionado de 2008 como nombre de variable en t/t9700/test.pl .


Puede ver esta transición a SHA 256 en progreso con Git 2.20 (Q4 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 Oct 2018) por Brian m . carlson ( bk2204) .
Véase el compromiso 6afedba (15 de octubre de 2018) de SZEDER Gábor ( szeder) .
(Fusionada porJunio ​​C Hamano - gitster- en el compromiso d829d49 , 30 de octubre de 2018)

reemplazar constantes codificadas de forma rígida

Reemplace varias constantes basadas en 40 con referencias a GIT_MAX_HEXSZo the_hash_algo, según corresponda.
Convierta todos los usos del GIT_SHA1_HEXSZa usar de the_hash_algomodo que sean apropiados para cualquier longitud de hash dada.
En lugar de utilizar una constante codificada de forma rígida para el tamaño de un ID de objeto hexadecimal, cambie para usar el puntero calculado desde parse_oid_hexesos puntos después del ID de objeto analizado.

GIT_SHA1_HEXSZse elimina / reemplaza con Git 2.22 (Q2 2019) y confirma d4e568b .


Esa transición continúa con Git 2.21 (Q1 2019), que agrega hash sha-256 y lo conecta a través del código para permitir la construcción de Git con el "NewHash".

Ver cometer 4b4e291 , cometer 27dc04c , cometer 13eeedb , cometer c166599 , cometer 37649b7 , cometer a2ce0a7 , cometer 50c817e , cometer 9a3a0ff , cometer 0dab712 , cometer 47edb64 (14 Nov 2018), y comprometerse 2f90b9d , cometer 1ccf07c (22 Oct 2018) por Brian m . carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 33e4ae9 , 29 de enero de 2019)

Agregar una implementación base de compatibilidad con SHA-256 (febrero de 2019)

SHA-1 es débil y necesitamos hacer la transición a una nueva función hash.
Durante algún tiempo, nos hemos referido a esta nueva función como NewHash.
Recientemente, decidimos elegir SHA-256 comoNewHash .
Las razones detrás de la elección de SHA-256 se describen en este hilo y en el historial de confirmación para el documento de transición de la función hash.

Agregue una implementación básica de SHA-256 basada en libtomcrypt, que es de dominio público.
Optimizarlo y reestructurarlo para cumplir con nuestros estándares de codificación.
Extraiga las funciones de actualización y final de la implementación del bloque SHA-1, ya que sabemos que funcionan correctamente con todos los compiladores. Esta implementación es más lenta que SHA-1, pero se introducirán implementaciones de mayor rendimiento en futuras confirmaciones.

Conecte SHA-256 en la lista de algoritmos hash y agregue una prueba de que el algoritmo funciona correctamente.

Tenga en cuenta que con este parche, todavía no es posible cambiar al uso de SHA-256 en Git.
Se necesitan parches adicionales para preparar el código para manejar un algoritmo hash más grande y se necesitan más correcciones de prueba.

hash: agregue una implementación SHA-256 usando OpenSSL

Ya tenemos rutinas OpenSSL disponibles para SHA-1, así que agregue rutinas para SHA-256 también.

En un Core i7-6600U, esta implementación SHA-256 se compara favorablemente con la implementación 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: agregue una implementación SHA-256 usando libgcrypt

Generalmente, se obtiene un mejor rendimiento de las rutinas criptográficas escritas en ensamblador que C, y esto también es cierto para SHA-256.
Además, la mayoría de las distribuciones de Linux no pueden distribuir Git vinculado contra OpenSSL por motivos de licencia.

La mayoría de los sistemas con GnuPG también lo tendrán libgcrypt, ya que es una dependencia de GnuPG.
libgcrypttambién es más rápido que la implementación de SHA1DC para mensajes de unos pocos KiB o más.

A modo de comparación, en un Core i7-6600U, esta implementación procesa fragmentos de 16 KiB a 355 MiB / s, mientras que SHA1DC procesa fragmentos equivalentes a 337 MiB / s.

Además, libgcrypt tiene licencia LGPL 2.1, que es compatible con la GPL. Agregue una implementación de SHA-256 que usa libgcrypt.


El esfuerzo de actualización continúa con Git 2.24 (Q4 2019)

Ver cometer aaa95df , comprometerse be8e172 , comprometerse 3f34d70 , comprometerse fc06be3 , comprometerse 69fa337 , comprometerse 3a4d7aa , comprometerse e0cb7cd , comprometerse 8d4d86b , comprometerse f6ca67d , comprometerse dd336a5 , cometen 894c0f6 , comprometerse 4439c7a , comprometerse 95518fa , comprometerse e84f357 , comprometerse fe9fec4 , comprometerse 976ff7e , cometen 703d2d4 , cometer 9d958cc , cometer 7962e04 , cometer fee4930(18 de ago de 2019) de brian m. carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 676278f , 11 de octubre de 2019)

En lugar de usar GIT_SHA1_HEXSZy constantes codificadas de forma rígida, cambie a using the_hash_algo.


Con Git 2.26 (Q1 2020), los scripts de prueba están listos para el día en que los nombres de los objetos usen SHA-256.

Ver cometer 277eb5a , comprometerse 44b6c05 , comprometerse 7a868c5 , comprometerse 1b8f39f , comprometerse a8c17e3 , comprometerse 8.320.722 , comprometerse 74ad99b , comprometerse ba1be1a , comprometerse cba472d , comprometerse 82d5aeb , comprometerse 3c5e65c , comprometerse 235d3cd , comprometerse 1d86c8f , comprometerse 525a7f1 , comprometerse 7a1bcb2 , comprometerse cb78f4f , cometen 717c939 , confirma 08a9dd8 , confirma 215b60b , confirma 194264c(21 de diciembre de 2019) de brian m. carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso f52ab33 , 05 de febrero de 2020)

Ejemplo:

t4204: hacer que el tamaño del hash sea independiente

Firmado por: brian m. carlson

Úselo en $OID_REGEXlugar de una expresión regular codificada.

Entonces, en lugar de usar:

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

Las pruebas están usando

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

Y OID_REGEXproviene de commit bdee9cd (13 de mayo de 2018) de brian m. carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 9472b13 , 30 de mayo de 2018, Git v2.18.0-rc0)

t/test-lib: introducir OID_REGEX

Firmado por: brian m. carlson

Actualmente tenemos una variable, $_x40,que contiene una expresión regular que coincide con una constante hexadecimal completa de 40 caracteres.

Sin embargo, con NewHash, tendremos identificadores de objetos de más de 40 caracteres.

En tal caso, $_x40será un nombre confuso.

Cree una $OID_REGEXvariable que siempre refleje una expresión regular que coincida con el ID de objeto apropiado, independientemente de la longitud del hash actual.

Y, todavía para las pruebas:

Ver cometer f303765 , comprometerse edf0424 , comprometerse 5db24dc , cometen d341e08 , comprometerse 88ed241 , comprometerse 48c10cc , comprometerse f7ae8e6 , cometen e70649b , cometen a30f93b , cometen a79eec2 , comprometerse 796d138 , comprometerse 417e45e , comprometerse dfa5f53 , comprometerse f743e8f , cometen 72f936b , comprometerse 5df0f11 , cometen 07877f3 , confirma 6025e89 , confirma 7b1a182 , confirma 94db7e3 ,commit db12505 (07 de febrero de 2020) por brian m. carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 5af345a , 17 de febrero de 2020)

t5703: hacer que la prueba funcione con SHA-256

Firmado por: brian m. carlson

Esta prueba utilizó un ID de objeto que tenía 40 caracteres hexadecimales de longitud, lo que provocó que la prueba no solo no pasara, sino que se bloqueara cuando se ejecutaba con SHA-256 como hash.

Cambie este valor a un ID de objeto ficticio fijo usando test_oid_inity test_oid.

Además, asegúrese de extraer un ID de objeto de la longitud adecuada utilizando cortar con campos en lugar de una longitud fija.


Algunas rutas de código recibieron una instancia de repositorio como parámetro para trabajar en el repositorio, pero pasaron la the_repositoryinstancia a sus destinatarios, que se ha limpiado (algo) con Git 2.26 (Q1 2020).

Consulte confirmar b98d188 , confirmar 2dcde20 , confirmar 7ad5c44 , confirmar c8123e7 , confirmar 5ec9b8a , confirmar a651946 , confirmar eb999b3 (30 de enero de 2020) por Matheus Tavares ( matheustavares) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 78e67cd , 14 de febrero de 2020)

sha1-file: permite check_object_signature()manejar cualquier repositorio

Firmado por: Matheus Tavares

Algunas personas que llaman a check_object_signature()pueden trabajar en repositorios arbitrarios, pero el repositorio no se pasa a esta función. En cambio, the_repositorysiempre se usa internamente.
Para corregir posibles inconsistencias, permita que la función reciba un repositorio de estructura y haga que los llamadores pasen el repositorio que se está manejando.

Residencia en:

sha1-file: pasar git_hash_algoahash_object_file()

Firmado por: Matheus Tavares

Permitir hash_object_file()trabajar en repositorios arbitrarios introduciendo un git_hash_algoparámetro. Cambie las personas que llaman que tienen un puntero de repositorio de estructura en su alcance para pasar el git_hash_algodesde dicho repositorio.
Para todas las demás personas que llaman, pase the_hash_algo, que ya se estaba utilizando internamente en hash_object_file().
Esta funcionalidad se utilizará en el siguiente parche para check_object_signature()poder trabajar en repositorios arbitrarios (que, a su vez, se utilizará para corregir una inconsistencia en object.c: parse_object ()).


1
Además, no olvide que Git v2.13.0 y posteriormente se trasladaron a una implementación SHA-1 reforzada por defecto, que no es vulnerable al ataque SHAtter. Ver stackoverflow.com/a/43355918/6309
VonC

1: Google produjo collision shattered.io en febrero de 2017 (costo estimado $ 110,000) 2: La Universidad Tecnológica de Nanyang produjo una colisión sha-mbles.github.io en enero de 2019 (costo estimado entre $ 11k - $ 45k) Git para superar SHA1
bristweb

@bristweb "Es hora de que Git pase de SHA1": estoy de acuerdo, y con Git 2.25 (lanzado hoy), ese movimiento es uno. git rev-parseahora puede imprimir qué hash se utilizará: stackoverflow.com/a/58862319/6309 . Y el árbol vacío tiene una nueva identificación SHA2: stackoverflow.com/a/9766506/6309
VonC

Con esta extensibilidad de algoritmo hash, CRC32 finalmente puede brillar de nuevo.
Walf

52

ACTUALIZACIÓN : La pregunta anterior y esta respuesta son de 2015. Desde entonces, Google ha anunciado la primera colisión SHA-1: https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html


Obviamente, solo puedo especular desde afuera mirando hacia adentro sobre por qué Git continúa usando SHA-1, pero estas pueden ser algunas de las razones:

  1. Git fue creación de Linus Torvald, y Linus aparentemente no quiere sustituir SHA-1 con otro algoritmo hash en este momento.
  2. Hace afirmaciones plausibles de que los ataques exitosos basados ​​en colisiones SHA-1 contra Git son mucho más difíciles que lograr las colisiones en sí mismos, y considerando que SHA-1 es más débil de lo que debería ser, no completamente roto, eso lo hace sustancialmente lejos de ser un Ataque viable al menos hoy. Además, señala que un ataque "exitoso" lograría muy poco si el objeto en colisión llega más tarde que el existente, ya que se supondría que el último es el mismo que el válido y se ignorará (aunque otros han señalado que podría ocurrir lo contrario).
  3. El cambio de software requiere mucho tiempo y es propenso a errores, especialmente cuando existe una infraestructura y datos basados ​​en los protocolos existentes que deberán ser migrados. Incluso aquellos que producen productos de software y hardware donde la seguridad criptográfica es el único punto del sistema todavía están en el proceso de migrar lejos de SHA-1 y otros algoritmos débiles en algunos lugares. Imagínense todos esos unsigned char[20]búferes codificados por todas partes ;-), es mucho más fácil programar para agilidad criptográfica al principio, en lugar de actualizarlo más tarde.
  4. El rendimiento de SHA-1 es mejor que los diversos hash SHA-2 (probablemente no sea un factor decisivo ahora, pero tal vez fue un punto de fricción hace 10 años), y el tamaño de almacenamiento de SHA-2 es mayor .

Algunos enlaces:

Mi opinión personal sería que, si bien los ataques prácticos probablemente están fuera de su alcance, e incluso cuando ocurren, las personas probablemente inicialmente los mitigarán con otros medios que no sean cambiar el algoritmo hash en sí, que si a usted le importa la seguridad, debería estar errando. por el lado de la precaución con sus elecciones de algoritmos, y revisando continuamente hacia arriba sus fortalezas de seguridad, porque las capacidades de los atacantes también van solo en una dirección, por lo que no sería prudente tomar a Git como un modelo a seguir, especialmente como su propósito en el uso de SHA-1 no pretende ser seguridad criptográfica.


7
"Puedes tener personas que intenten ser maliciosas. No tendrán éxito. N̶o̶b̶o̶d̶y̶ ̶h̶a̶s̶ ̶b̶e̶e̶n̶ ̶a̶b̶l̶e̶ ̶t̶o̶ ̶b̶r̶e̶a̶k̶ ̶SSH̶A̶-̶1 no lo es, pero el punto es la característica de seguridad, en lo que respecta a SHA-1̶. . Es puramente una comprobación de coherencia ". -Linus Torvalds
Shakti

9
Los hashes de Git deben ser seguros para las firmas seguras que las personas colocan en su código para verificar cualquier cosa. Estas firmas firman un árbol enorme de estos hashes. Si alguna rama de ese árbol choca, se puede insertar código malicioso mientras pasa la firma. Git se usa increíblemente ahora. Se necesita una actualización de hash.
fuzzyTew

Dos cosas a considerar a la luz de "destrozado": 1. Uso de SHA-1. - SHA-1 se utiliza como una suma de comprobación glorificada para comprobar contra daños accidentales. - SHA-1 se usa como una función generadora para dar un número hexadecimal útil (algo pequeño) para designar objetos dentro de su almacén direccionable de contenido (es decir: generador de nombre de archivo glorificado). - Son confirmaciones firmadas que son responsables de la seguridad (es decir: firma de criptografía de clave pública. NO sha-1)
DrYak

2. Viabilidad: después de toneladas de tiempo de GPU, Google ha logrado generar un par de series de bloques. - ambos hash a la misma suma SHA-1 (esa es la colisión) - son completamente basura (será difícil justificar por qué su confirmación tiene un bloque gigante de basura binaria en el medio). - la demo destrozada se basa en tener una forma de presentar un comportamiento diferente dependiendo de cuál de los archivos basura binarios aleatorios esté presente. Eso es posible con PDF (que tiene un lenguaje de secuencias de comandos integrado oculto detrás). Eso va a ser mucho más difícil de fuente simple (pensar solapada C Concurso)
Dryak

@DrYak For 2: supongamos que está rastreando documentos de Photoshop con un campo de comentario en ellos. U otros archivos multimedia con metaetiquetas. Ese es un caso típico en el desarrollo de juegos. Pero normalmente no se comprobarán en cada cambio: ¿por qué comprobar la metaetiqueta si el mensaje de confirmación dice "optimizar por tamaño"?
Arne Babenhauserheide

5

Esta es una discusión sobre la urgencia de migrar desde SHA1 para Mercurial, pero también se aplica a Git: https://www.mercurial-scm.org/wiki/mpm/SHA1

En resumen: si no eres extremadamente diligente hoy, tienes vulnerabilidades mucho peores que sha1. Pero a pesar de eso, Mercurial comenzó hace más de 10 años a prepararse para migrar desde sha1.

Se ha trabajado durante años para adaptar las estructuras de datos y los protocolos de Mercurial para los sucesores de SHA1. El espacio de almacenamiento se asignó para hashes más grandes en nuestra estructura de revlog hace más de 10 años en Mercurial 0.9 con la introducción de RevlogNG. El formato bundle2 introducido más recientemente admite el intercambio de diferentes tipos de hash a través de la red. Las únicas piezas restantes son la elección de una función de reemplazo y la elección de una estrategia de compatibilidad con versiones anteriores.

Si git no migra de sha1 antes que Mercurial, siempre puede agregar otro nivel de seguridad manteniendo un espejo Mercurial local con hg-git .


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.