una - ¿qué herramienta podemos hacer para tener un mayor control de nuestros proyecto en github?
¿Cómo uso correctamente libsodium para que sea compatible entre versiones? (2)
Estoy planeando almacenar un montón de registros en un archivo, donde cada registro se firma con libsodium . Sin embargo, me gustaría que las versiones futuras de mi programa puedan verificar firmas de la versión actual, y viceversa.
Para la versión actual de Sodium, las firmas se hacen usando el algoritmo Ed25519. Me imagino que la primitiva predeterminada puede cambiar en las nuevas versiones de Sodio (de lo contrario, libsodium no expondría una manera de elegir una en particular, creo).
Debería...
- Utilice siempre la primitiva predeterminada (es decir,
crypto_sign
) - Use una primitiva específica (es decir,
crypto_sign_ed25519
) - Haga (1), pero almacene el valor de
sodium_library_version_major()
en el archivo (en un campo dedicado de ''versión de sodio'' o en un campo general de ''revisión de formato de archivo'') y salga si la versión que se está ejecutando es más baja - Hacer (3), pero también almacenar
crypto_sign_primitive()
- Hacer (4), pero también almacenar
crypto_sign_bytes()
y amigos
... o debería hacer algo completamente diferente?
Mi programa estará escrito en C.
Primero identifiquemos el conjunto de posibles problemas y luego intentemos resolverlo. Tenemos algunos datos (un registro) y una firma. La firma se puede calcular con diferentes algoritmos. El programa puede evolucionar y cambiar su comportamiento, el libsodium también puede (independientemente) evolucionar y cambiar su comportamiento. En el frente de generación de firmas tenemos:
-
crypto_sign()
, que utiliza algún algoritmo predeterminado para producir firmas (en el momento de escribir solo invocacrypto_sign_ed25519()
) -
crypto_sign_ed25519()
, que produce firmas basadas en el algoritmo específicoed25519
Supongo que para un algoritmo en particular con los mismos datos de entrada y la misma clave, siempre obtendremos el mismo resultado, ya que son matemáticos y cualquier desviación de esta regla haría que la biblioteca fuera completamente inutilizable.
Echemos un vistazo a las dos opciones principales:
- Usar
crypto_sign_ed25519()
todo el tiempo y nunca cambiar esto. No es una opción tan mala, porque es simple y mientrascrypto_sign_ed25519()
exista en libsodium y sea estable en su salida, no tiene nada de qué preocuparse con la firma estable de tamaño fijo y la sobrecarga de administración cero para esto. Por supuesto, en el futuro, alguien puede descubrir algún problema horrible con este algoritmo y, si no está preparado para cambiar el algoritmo, podría significar un problema horrible para usted. - Usando
crypto_sign()
. Con esto, de repente tenemos muchos problemas, porque el algoritmo puede cambiar, por lo que debe almacenar algunos metadatos junto con la firma, lo que abre un conjunto de preguntas:- que almacenar?
- ¿deberían estos metadatos ser de nivel de registro o de nivel de archivo?
¿Qué tenemos en las funciones mencionadas para el segundo enfoque?
-
sodium_library_version_major()
es una función que nos dice la versión de la API de la biblioteca. No está directamente relacionado con los cambios en los algoritmos soportados / predeterminados por lo que es de poca utilidad para nuestros problemas. -
crypto_sign_primitive()
es una función que devuelve una cadena que identifica el algoritmo utilizado encrypto_sign()
. Es una combinación perfecta para lo que necesitamos, porque supuestamente su salida cambiará exactamente en el momento en que el algoritmo cambie. -
crypto_sign_bytes()
es una función que devuelve el tamaño de la firma producida porcrypto_sign()
en bytes. Eso es útil para determinar la cantidad de almacenamiento necesario para la firma, pero puede permanecer igual si el algoritmo cambia, por lo que no son los metadatos que necesitamos almacenar de forma explícita.
Ahora que sabemos qué almacenar, hay una cuestión de procesar los datos almacenados. Debe obtener el nombre del algoritmo y usarlo para invocar la función de verificación coincidente. Desafortunadamente, por lo que veo, libsodium en sí mismo no proporciona ninguna forma simple de obtener la función adecuada dado el nombre del algoritmo (como EVP_get_cipherbyname()
o EVP_get_digestbyname()
en openssl), por lo que necesita hacer uno usted mismo (que por supuesto debería fallar por nombre desconocido). Y si tiene que hacer uno usted mismo, tal vez sería aún más fácil almacenar algún identificador numérico en lugar del nombre de la biblioteca (sin embargo, más código).
Ahora volvamos a nivel de archivo vs nivel de registro. Para resolverlo, hay otras dos preguntas para formular: ¿puede generar nuevas firmas para registros antiguos en un momento dado (es técnicamente posible, está permitido por la política) y necesita anexar nuevos registros a archivos viejos?
Si no puede generar nuevas firmas para registros antiguos o necesita agregar nuevos registros y no desea la penalización de rendimiento de la regeneración de firmas, entonces no tiene muchas opciones y debe:
- tener un campo de tamaño dinámico para su firma
- almacenar el algoritmo (campo de cadena dinámico o ID interno (para su aplicación)) utilizado para generar la firma junto con la firma misma
Si puede generar nuevas firmas o especialmente si no necesita anexar nuevos registros, puede salirse con un enfoque de nivel de archivo más simple cuando almacena el algoritmo utilizado en un campo de nivel de archivo especial y, si el algoritmo de la firma cambia , regenere todas las firmas al guardar el archivo (o use la anterior al agregar nuevos registros, eso también es más una pregunta de política de compatibilidad).
¿Otras opciones? Bueno, ¿qué tiene de especial crypto_sign()
? Es que su comportamiento no está bajo su control, los desarrolladores de libsodium eligen el algoritmo para usted (sin duda eligen uno bueno), pero si tiene información de control de versiones en su estructura de archivos (no específica de la firma, quiero decir) nada le impide hacer su propia elección particular y usar un algoritmo con una versión de archivo y otra con otra (con código de conversión cuando sea necesario, por supuesto). Nuevamente, eso también se basa en la suposición de que puede generar una nueva firma y eso está permitido por la política.
Lo que nos lleva de vuelta a las dos opciones originales con la pregunta de si vale la pena hacer todo eso en comparación con solo usar crypto_sign_ed25519()
. Eso depende principalmente de la duración de tu programa, probablemente diría (solo como una opinión) que si son menos de 5 años, entonces es más fácil usar solo un algoritmo en particular. Si puede ser fácilmente de más de 10 años, entonces no, realmente necesita poder sobrevivir al algoritmo (y probablemente incluso a toda la biblioteca de cifrado).
Solo usa la API de alto nivel.
Las funciones de la API de alto nivel no van a usar un algoritmo diferente sin que se golpee la versión principal de la biblioteca.
El único cambio radical que se puede esperar en libsodium 1.xy es la eliminación de las funciones en desuso / no documentadas (que ni siquiera existen en las versiones actuales compiladas con el parámetro --enable-minimal
). Todo lo demás seguirá siendo compatible con versiones anteriores.
Se pueden introducir nuevos algoritmos en las versiones 1.xy sin envoltorios de alto nivel, y se estabilizarán y expondrán a través de una nueva API de alto nivel en libsodium 2.
Por lo tanto, no se moleste en llamar a crypto_sign_ed25519()
. Solo usa crypto_sign()
.