Cómo usar CRC-16 para verificar la memoria del programa en el software C incorporado

CRC es una división larga . Toma el mensaje, o paquete de software, como un número enormemente largo y lo divide repetidamente a la antigua división larga, restando el divisor hasta que el MSB sea cero, y el resultado final, el CRC, es el resto . La diferencia con la división larga ordinaria es que todas las sustracciones se realizan en el módulo-2, es decir, haciendo XOR al divisor con el siguiente dividendo, que es muy rápido y fácil con la lógica digital. El polinomio generador de CRC o “número mágico” siempre tiene un MSB de 1, por lo que si el mensaje no tiene un MSB de 1, omite el XOR y cambia el mensaje hasta que lo tenga. Es extremadamente rápido Lo que lo hace útil es que si agrega el resto al mensaje, la próxima vez que lo CRC, la división es exacta, es decir, el resto es cero. Hay variaciones en esto, como sembrar el CRC con diferentes números al principio, pero el punto es que siempre le dará una respuesta predecible siempre que el mensaje no cambie.

Otras respuestas dicen que el CRC-16 no es lo suficientemente bueno. Hay 65.536 resultados posibles para un CRC-16, por lo que es teóricamente posible que en un programa largo, varias variaciones den el mismo resultado, pero si está pirateando un ejecutable es mucho trabajo modificarlo de una manera para producir un resultado previsto . No imposible, solo muy difícil y lento. Aún así, es muy poco más trabajo usar un CRC-32 para dar 4 mil millones de resultados posibles. Una función hash como SHA es aún más segura, pero requiere mucho más trabajo para implementar. Está cifrando efectivamente el programa mediante un algoritmo complicado y termina con un resumen , que es otro tipo de resto.

La forma de hacerlo es incluir la rutina CRC en algún lugar del programa, configurada para CRC toda la ROM de principio a fin. Luego, cuando haya terminado el archivo hexadecimal, ejecute el algoritmo CRC en todo el programa de principio a fin, excepto los dos últimos bytes (4 bytes si usa CRC-32). Tome el resultado de esa operación CRC e insértelo como los últimos dos (o cuatro) bytes del archivo hexadecimal. Prográmelo en el dispositivo. Ahora, cuando ejecuta la rutina interna de CRC, que hace inmediatamente que el programa arranca, tomará los últimos bytes que acaba de programar y terminará en cero, o el resultado previsto si utilizó una semilla diferente de cero. Su rutina interna debería bloquearse o detenerse si el CRC no produce el resultado esperado.

Debo decir esto antes de que alguien lo comente: un CRC de n bits en realidad usa un generador de bits ( n + 1 ), pero dado que el MSB siempre es 1, siempre se asume y no se menciona.

Trivialidades:

  • El CRC de una cadena infinita de 0 siempre es 0. Puede agregar ceros infinitos al final de un mensaje sin cambiar el CRC.
  • Un generador de números pseudoaleatorios de registro de desplazamiento es solo un generador CRC alimentado con una cadena infinita de 1.

¿Está tratando de verificar que el código no tiene errores involuntarios o está tratando de verificar que el código no haya sido adulterado intencionalmente?

CRC-16 verificará estadísticamente que el código no haya introducido errores involuntarios.

Hay mejores métodos, pero todos son estadísticos.

Un método criptográfico, como MD5, asegura que el código no haya sido adulterado intencionalmente.

También es estadístico, pero es más difícil lograr que tenga el valor correcto después de adulterarlo, porque es computacionalmente difícil hacerlo.

Aún puedes hacerlo. Hay un gran ataque contra MD5 que se publicó en la literatura académica china usando “interferencia”. Admiro por completo a los matemáticos que se le ocurrió; vieron en las esquinas que sabía que estaban allí, pero no pude ver a mi alrededor.

La mayoría de las personas que quieren hackearlo pueden ver en las esquinas. Aquellos de nosotros que podemos, admiramos a los que pueden ver en las esquinas que nosotros no podemos o donde lleva mucho tiempo.

(Pude haber visto esa esquina en particular; me habría costado un esfuerzo que no estaba dispuesto a gastar de mi parte)


Todo se reduce a lo valioso que es ver más allá de su esquina.

Si vale la pena, puedo hacer CRC-16 de forma incremental. Es fácil.

Si está tratando de “hacer” un “camino de seda”, alguien como yo (probablemente no yo … probablemente) verá uno o dos derivados.

No va a suceder a menos que seas un genio de las matemáticas.

  1. Como otros ya han mencionado, use una función de suma de verificación más robusta que CRC16 si es posible. Ya sea CRC32, SHA256, lo que sea, todos brindan la misma funcionalidad, solo que con diferentes resultados. Llamemos al proceso genérico “suma de verificación”.
  2. En el proceso de compilación de la imagen del firmware, ejecute la suma de comprobación en todo el binario que se cargará en la RAM al arrancar. Almacene el resultado de la suma de verificación en un lugar “seguro” y no volátil en el sistema, por ejemplo, una EEPROM pequeña que se pueda hacer de solo lectura al quitar un puente (o escribir una vez por diseño). Retire el puente en sistemas fabricados en la antigua.
  3. En un sistema operativo, en el arranque del sistema o incluso de forma continua, aplique la misma función de suma de comprobación sobre el binario en ejecución. Compare la suma de comprobación resultante con la copia de solo lectura guardada. Si las dos sumas de verificación difieren, entonces sabes que hay un problema. O la copia operativa, la suma de comprobación precalculada o ambas se han dañado.

Entonces, ese es el concepto. La práctica real difiere debido a los dictados del hardware real y el software del sistema.

CRC-16 probablemente ya NO sea la respuesta correcta, ya que realmente no es lo suficientemente grande como para cubrir fácilmente fragmentos útiles. Está bien para proteger un paquete pequeño (1500B) pero no es lo que desea para verificar un segmento de texto grande.

Probablemente debería usar algo más fuerte, como CRC-32, MD5 o SHA-256.

La idea básica es que cada una de estas funciones actúa como un hash. Lo introduce en la memoria del programa y calcula un número. Estas funciones tienen la propiedad de que si cambia la entrada aunque sea un poco, la salida es muy diferente. Si el resultado sobre la memoria del programa no coincide con lo que era cuando lo ejecutó en un entorno ‘limpio’, entonces es una señal bastante clara de que alguien ha alterado la memoria del programa.

Depende del tamaño de la memoria …

CRC16 es bastante pequeño para cualquier cosa. CRC 32 o 64 es mucho mejor.

El procedimiento básico es sumar todos los datos + los valores CRC. El resultado debe ser cero. Si no es así, entonces hay un error. Ya sea en la memoria o en el valor CRC almacenado.

El lugar donde usé un CRC16 fue en el día en que se usó cinta de papel … con registros de 56 bytes. El CRC 16 funciona bastante bien entonces. Los errores no se pierden en la suma.

Con grandes cantidades de datos para sumar, es completamente posible que un CRC 16 pierda el error (especialmente si fue al principio) y usted tendría un problema ya que el CRC validado …