Cifrado de respaldo seguro con OpenSSL

13

Lo sé, el consejo general es "mantener las manos alejadas de las cosas criptográficas". Y la forma estándar de cifrar datos de copia de seguridad de forma segura sería utilizando GnuPG. Sin embargo, para un ejercicio bastante académico, me gustaría pensar en un protocolo que funcionaría solo con las herramientas estándar de OpenSSL (es decir, dgst, enc, rsautl & Co) invocado desde un shell POSIX.

El escenario incluye un sistema más o menos confiable y desde el cual se crean las copias de seguridad, esto podría e. sol. Ser un servidor de correo o archivos. Luego hay un almacenamiento que no es 100% confiable (por ejemplo, un almacenamiento en la nube o un servidor de respaldo que no está completamente bajo mi control). Por lo tanto, el propósito del cifrado es proteger la confidencialidad y la integridad de los datos mientras se almacenan en el almacenamiento no confiable. Esta protección también debería funcionar en caso de que el sistema de confianza se vea comprometido, al menos para los datos almacenados antes de que se comprometiera el sistema de confianza.

Así que aquí hay un tipo de protocolo que debería cumplir con los criterios mencionados anteriormente:

Paso 1: Par de claves RSA

Este paso solo debe realizarse una vez. Se necesita un par de claves RSA. Este par de claves no se creará en el sistema "confiable", sino en un cuadro realmente confiable (por ejemplo, una estación de trabajo confiable o en cualquier lugar en el que confíe para mantener su conjunto de claves GPG). Dado que la clave privada solo es necesaria para la recuperación, nunca ingresará a los dominios del sistema confiable o del almacenamiento no confiable. El tamaño de la clave debe ser 4096 bits o superior (veremos eso más adelante). OpenSSL generalmente ofrece la generación de claves y la separación mediante esos comandos:

  

EDIT: cambió a PKCS # 8 para las claves, probablemente sea más resistente a los ataques de fuerza bruta

openssl genpkey -aes-256-cbc -algorithm RSA -pkeyopt 'rsa_keygen_bits:8192' -out private.key
openssl pkey -in private.key -out public.key -pubout

Paso 2: generar secretos de sesión

Para cada proceso de cifrado, se generarán secretos dedicados (clave, vector de inicialización y sal):

  

EDITAR: se eliminó la sal según el comentario de Ctulhu

key=$(openssl rand -hex 32)
iv=$(openssl rand -hex 16)
hmacpw=$(openssl rand -base64 48)

Tenga en cuenta: soy consciente de que esto tendrá los secretos sin proteger en la memoria de la máquina de confianza. Sin embargo, si un atacante tiene acceso a la máquina de manera que pueda hojear la memoria del proceso de copia de seguridad, probablemente ya tenga acceso a los datos para estar protegidos por estos secretos.

Paso 3: Comprimir y cifrar

Los datos se comprimirán antes del cifrado. De todos modos, se requiere compresión, por lo que considero una buena idea hacerlo antes de cifrar los datos:

  

EDITAR: se eliminó la sal según el comentario de Ctulhu

data-generator | xz -zc | openssl enc -e -aes-256-ctr -K $key -iv $iv -out message.enc

Paso 4: generar HMAC y empaquetar las claves

El último paso sería generar un HMAC de los datos simplemente encriptados y empaquetarlos junto con los secretos de la sesión en un archivo encriptado RSA, utilizando la clave pública para el cifrado:

  

EDITAR: se eliminó la sal según el comentario de Ctulhu

hmac=$(openssl dgst -sha512 -hmac $hmacpw -hex message.enc | sed 's/^.*=[[:space:]]//g')
echo "${key}:${iv}:${hmacpw}:${hmac}" | openssl rsautl -inkey public.key -pubin -encrypt -out message.key

Y aquí resulta obvio por qué la clave RSA tenía que ser tan grande: los dígitos hexadecimales en las cadenas de shell se cuentan como un byte cada uno, no como medio byte. Por lo tanto, el tamaño de la cadena de clave suma hasta (2x32 + 2x16 + 64 + 128 + 5) = 293 bytes = 2344 bits.

Una vez más, soy consciente de que exponer secretos en una línea de comando generalmente es una mala idea, pero dadas las circunstancias, no veo cómo esto pueda comprometer la confidencialidad o integridad de los datos que están disponibles en texto sin formato en dicho sistema. donde un atacante podría comprometer mucho más su privacidad o integridad. Sin embargo, si realmente quisiera implementar esto, preferiría utilizar canalizaciones con nombre para evitar que los secretos aparezcan en la lista de procesos.

Ahora mis preguntas:

  1. ¿Qué me perdí? ¿Ves algún defecto o posible vector de ataque que no haya notado todavía?
  2. ¿Sería más seguro crear una firma con openssl dgst -sha512 -sign private.key -out message.sig message.enc , dado que esto requeriría que la clave privada residiera en el sistema más o menos confiable?
pregunta Daemotron 12.08.2015 - 12:45
fuente

1 respuesta

1
  1. Para la pregunta sobre lo que podría haberse perdido:

En el momento en que cifraste los datos en el servidor, puedes usar rsync para sincronizar de forma segura los datos con la copia de seguridad.

rsync -aHSv --del --progress ~/<encrypted-data> user@remote-backup-server:/<destination-directory>./ -n

El uso de --del es eliminar cosas antiguas en el destino remoto (puedes eliminar esa opción de manera segura si quieres mantener todo el historial).

  1. Para la pregunta sobre seguridad:

La ventaja de hacer cosas con rsync es que puedes asegurar que backup server firewall funcione solo con algo de IP en algunos ports y usar tu RSA Keys con ~/.ssh/authorized_keys

  1. ¿OpenSSL o LibreSSL?

Creo que ese punto podría ser interesante para excavar como se explica en security.stack

    
respondido por el aurelien 06.11.2016 - 20:08
fuente

Lea otras preguntas en las etiquetas