Mantener la confidencialidad de los datos y el código en las imágenes del contenedor
En los últimos años, la industria de la nube ha experimentado un cambio importante, pasando de implementar aplicaciones monolíticas en máquinas virtuales a dividir las aplicaciones en componentes más pequeños (microservicios) y empaquetarlos en contenedores. La popularidad de la contenedorización hoy en día está impulsada en gran medida por el funcionamiento de Docker. Docker es la empresa que se ha convertido en la principal fuerza impulsora detrás de los contenedores: ha proporcionado una herramienta fácil de usar para crear y ejecutar contenedores Docker y un registro de contenedores Docker para el desafío de la distribución.
El éxito de la tecnología de contenedorización depende principalmente de la seguridad de los contenedores en varias etapas de su ciclo de vida. Una de las preocupaciones de seguridad es la presencia de vulnerabilidades dentro de contenedores individuales. Para identificarlos, las canalizaciones de DevOps utilizadas para crear contenedores se complementan con escáneres que buscan paquetes con posibles vulnerabilidades en los contenedores y alertan a sus propietarios o técnicos si los encuentran. Vulnerability Advisor en IBM Cloud es un ejemplo de tal utilidad.
Otro aspecto de la seguridad es asegurarse de que el contenedor que se está lanzando sea el que desea y que no haya sido modificado. Este problema se aborda mediante el uso de firmas digitales almacenadas en Notario, que protegerán los contenedores de cualquier modificación.Docker Notary es un ejemplo de un repositorio público que almacena firmas de imágenes. Con Notario, un cliente puede verificar la firma de la imagen del contenedor para asegurarse de que la imagen del contenedor no se haya alterado desde que se firmó con la clave del propietario o del técnico de servicio.
Otro problema de seguridad potencial es el aislamiento de contenedores. Las tecnologías de seguridad en tiempo de ejecución de Linux, como los espacios de nombres, los cgroups, las capacidades de Linux y los perfiles SELinux, AppArmor y Seccomp, ayudan a limitar los procesos de contenedor y a aislar los contenedores entre sí en el tiempo de ejecución.
Este artículo aborda el problema de seguridad empresarial aún candente con respecto a la privacidad de los datos y el código en las imágenes de contenedores. El principal objetivo de seguridad al trabajar con imágenes de contenedor es permitir la creación y distribución de imágenes de contenedor cifradas para que solo estén disponibles para un conjunto específico de destinatarios. En este caso, otros pueden tener acceso a estas imágenes, pero no podrán ejecutarlas ni ver los datos confidenciales que contienen. El cifrado de contenedores se basa en la criptografía existente, como las tecnologías de cifrado Rivest-Shamir-Adleman (RSA), la curva elíptica y el Estándar de cifrado avanzado (AES), también conocido como Rijndael, un algoritmo de cifrado de bloque simétrico.
Introductorio
Para aprovechar al máximo este artículo, debe estar familiarizado con los contenedores e imágenes de contenedores de Linux, y comprender los conceptos básicos de seguridad.
Trabajo relacionado sobre cifrado y contenedores
Hasta donde sabemos, no hay trabajo en el campo del cifrado de imágenes de contenedores. Sin embargo, existen muchas implementaciones y productos que admiten la privacidad de los datos y el cifrado antirrobo a través del sistema de archivos, el dispositivo de bloqueo o el cifrado de hardware. Este último se implementa mediante discos de autocifrado. También hay imágenes de máquinas virtuales encriptadas.
Los sistemas de archivos cifrados existen en muchos sistemas operativos de las empresas y pueden admitir el montaje de particiones y directorios cifrados. Los sistemas de archivos cifrados pueden incluso admitir el arranque desde una unidad de arranque cifrada. Linux admite el cifrado de dispositivos de bloque mediante el controlador dm-encrypt; ecryptfs es un ejemplo de un sistema de archivos cifrado. Otras soluciones de cifrado de archivos disponibles para Linuxfuente abierta. En Windows, el sistema de archivos NTFS v3.0 admite el cifrado. Además, muchos fabricantes crean discos autocifrados. Para las imágenes de máquinas virtuales, existe una solución similar a los discos encriptados. El emulador de máquina QEMU (PC) de código abierto y los productos de virtualización de VMware admiten imágenes de máquinas virtuales cifradas.
El cifrado de datos generalmente tiene como objetivo proteger contra el robo de datos mientras el sistema está fuera de línea. Una tecnología relacionada es firmar la imagen del contenedor con una clave proporcionada por el cliente y el servidor de Docker Notary. El servidor Docker Notary funciona muy cerca del registro de imágenes del contenedor. Los usuarios de la herramienta cliente de Docker tienen la opción de firmar la imagen del contenedor y cargar la firma en sus cuentas a través de Docker Notary. Durante este proceso, la firma se vincula a la imagen del contenedor a través del nombre de ruta a la imagen y sus versiones. La firma se crea mediante una función hash que se calcula en base a la descripción de todo el contenido de la imagen. Esta descripción se denomina manifiesto de imagen de contenedor.La tecnología de firma de imágenes de contenedores resuelve el problema de proteger las imágenes de contenedores del acceso no autorizado y ayuda a determinar el origen de la imagen del contenedor.
Estructura
El ecosistema de Docker evolucionó para estandarizar los formatos de imagen de contenedor utilizando el grupo de estándares Open Container Initiative (OCI), que ahora controla el formato de tiempo de ejecución del contenedor (runtime-spec) y el formato de imagen del contenedor (image-spec). Dado que el trabajo del equipo requería una extensión del formato de imagen de contenedor existente, identificamos una extensión del estándar para admitir imágenes encriptadas. Las siguientes secciones describen la imagen del contenedor existente y el formato de extensión.
En el nivel superior, un contenedor puede constar de un documento de notación de objetos JavaScript (JSON), que es una lista de manifiestos de imágenes. Por ejemplo, puede utilizar esta lista de manifiestos cuando se utilizan varias arquitecturas o plataformas para la imagen del contenedor. La lista de manifiestos contiene enlaces a manifiestos de contenedores, uno para cada combinación de arquitectura y sistema operativo. Por ejemplo, las arquitecturas compatibles incluyen amd64, arm y ppc64le, y los sistemas operativos compatibles incluyen Linux o Windows. En la siguiente captura de pantalla se muestra un ejemplo de una lista de manifiestos:
El campo mediaType describe el formato exacto del documento especificado. Esta lista de manifiestos permite una futura expansión y selección del analizador apropiado para el documento involucrado.
El nivel debajo de la lista de manifiestos es el manifiesto. El manifiesto también es un documento JSON y contiene una lista ordenada de referencias a capas de imágenes. Estos enlaces contienen mediaType que describe el formato de la capa. El formato puede describir si la capa está comprimida y, de ser así, cómo. Por ejemplo, cada nivel se puede guardar como un archivo .tar que contiene archivos que se agregaron en una etapa específica de la compilación al ejecutar la compilación de Docker en un Dockerfile. Las capas a menudo se empaquetan con archivos .gzip comprimidos para mejorar la eficiencia del almacenamiento. En la siguiente captura de pantalla se muestra un ejemplo de un documento de manifiesto:
Como se muestra, los manifiestos y las capas se referencian a través de un "resumen", que suele ser una función hash sha256 en los documentos JSON. Los manifiestos y las capas generalmente se almacenan como archivos en el sistema de archivos. A menudo, los nombres de archivo son funciones hash sobre el contenido, lo que facilita su búsqueda y carga. La consecuencia de este método hash es que un pequeño cambio en el documento referenciado provoca cambios en todos los documentos que hacen referencia a él, hasta la lista de manifiestos.
Como parte del proyecto de nuestro equipo, creamos el cifrado de imágenes basado en un esquema de cifrado híbrido utilizando claves públicas y simétricas. Las claves simétricas se utilizan para el cifrado masivo de datos (utilizado para el cifrado multinivel) y las claves públicas se utilizan para empaquetar claves simétricas. Usamos tres tecnologías diferentes de cifrado de clave pública: OpenPGP, JSON Web Encryption (JWE) y PKCS # 7.
OpenPGP
OpenPGP es una tecnología de encriptación y firma que se usa comúnmente para encriptar y firmar mensajes de correo electrónico. Las comunidades de código abierto también lo usan a menudo para firmar confirmaciones (etiquetas) de código fuente en repositorios de git. Es un estándar de Internet definido por IETF en RFC480 y puede verse como una versión abierta de la tecnología PGP patentada anterior.
OpenPGP tiene su propio formato para claves RSA. Las claves generalmente se almacenan en un archivo de anillo de claves y se pueden importar desde archivos de claves OpenPGP simples. El aspecto más conveniente del llavero de OpenPGP es que las claves públicas se pueden vincular a las direcciones de correo electrónico de sus propietarios. Puede trabajar con varios destinatarios de un mensaje simplemente seleccionando una lista de destinatarios por sus direcciones de correo electrónico, que luego aparecen en las claves públicas de esos destinatarios. Además, se ha creado una web de confianza en torno a esta tecnología: se pueden encontrar las claves públicas de muchos usuarios, ordenadas por sus direcciones de correo electrónico. Por ejemplo, estas claves se utilizan a menudo para firmar etiquetas git.
Puede utilizar el formato de mensaje cifrado OpenPGP para cifrar un mensaje masivo a varios destinatarios. El encabezado del mensaje OpenPGP contiene un bloque para cada destinatario. Cada bloque contiene un identificador de clave de 64 bits que le dice al algoritmo de descifrado dónde intentar descifrar la clave privada correspondiente. Una vez que se descifra el blob cifrado dentro del bloque, se muestra la clave simétrica que se puede utilizar para descifrar el mensaje masivo. El blob de clave pública cifrada de cada destinatario exhibe la misma clave simétrica.
Usamos OpenPGP de manera similar, pero en este caso, el mensaje encriptado que envía no es una capa. En cambio, contiene un documento JSON, que a su vez contiene una clave simétrica que se usa para cifrar y descifrar tanto la capa como el vector de inicialización. A esta clave la llamamos clave de cifrado de capa (LEK) y es una forma de clave de cifrado de datos. La ventaja de este método es que solo necesitamos un LEK. Con LEK, ciframos la capa para uno o más destinatarios. Cada destinatario (imagen de contenedor) puede tener un tipo de clave diferente y no es necesario que sea una clave OpenPGP. Por ejemplo, podría ser una simple clave RSA. Siempre que tengamos la capacidad de usar esta clave RSA para cifrar el LEK, podemos trabajar con varios destinatarios con diferentes tipos de claves.
Cifrado web JSON (JWE)
El cifrado web JSON, también conocido como JWE, es otro estándar de Internet IETF y se define en RFC7516 . Es un estándar de cifrado más nuevo que OpenPGP y, por lo tanto, utiliza cifrados de bajo nivel más recientes diseñados para cumplir con requisitos de cifrado más estrictos.
A mayor escala, JWE funciona de manera similar a OpenPGP en el sentido de que también mantiene una lista de destinatarios y el envío masivo de un mensaje cifrado con una clave simétrica a la que todos los destinatarios del mensaje tienen acceso. Los destinatarios de un mensaje JWE pueden tener diferentes tipos de claves, como claves RSA, tipos de clave de curva elíptica específicos para cifrado y claves simétricas. Como se trata de un estándar más nuevo, aún es posible ampliar el JWE para admitir claves en dispositivos de hardware como TPM o módulos de seguridad de hardware (HSM) utilizando PKCS # 11 o interfaces de protocolo de interoperabilidad y administración de claves (KMIP). El JWE se usa de manera similar a OpenPGP si los destinatarios tienen claves RSA o curvas elípticas.En el futuro, podríamos ampliarlo para admitir claves simétricas como KMIP dentro de HSM.
PKCS # 7
PKCS # 7, también conocido como sintaxis de mensajes criptográficos (CMS), se define en IEFT RFC5652 . Según Wikipedia sobre el CMS, "se puede utilizar para firmar, digerir, autenticar o cifrar digitalmente cualquier forma de datos digitales".
Es similar a las dos tecnologías descritas anteriormente en que permite múltiples destinatarios y el cifrado de mensajes masivos. Por lo tanto, lo usamos como otras tecnologías, pero solo para los destinatarios que proporcionan certificados para claves de cifrado.
Para admitir las tecnologías de cifrado descritas anteriormente, hemos ampliado el documento de manifiesto para incluir la siguiente información:
- Los mensajes OpenPGP, JWE y PKCS # 7 se almacenan en un mapa de anotaciones, que es parte del manifiesto.
- Cada capa especificada contiene un mapa. Un mapa de anotaciones es básicamente un diccionario con cadenas como claves y cadenas como valores (pares clave-valor).
Para admitir el cifrado de imágenes, hemos definido las siguientes claves:
- org.opencontainers.image.enc.keys.openpgp
- org.opencontainers.image.enc.keys.jwe
- org.opencontainers.image.enc.keys.pkcs7
El valor al que hace referencia cada clave contiene uno o más mensajes cifrados para la tecnología de cifrado correspondiente. Dado que estos mensajes pueden estar en formato binario, están codificados en base64. Una capa cifrada debe tener al menos una de estas anotaciones, pero puede tener todas, si su destinatario tiene una cantidad suficiente de tipos diferentes de claves.
Para determinar que la capa estaba cifrada con LEK, ampliamos los tipos de medios existentes con el sufijo '+ cifrado', como se muestra en los siguientes ejemplos:
- application / vnd.docker.image.rootfs.diff.tar + encriptado
- application / vnd.docker.image.rootfs.diff.tar.gzip + encriptado
Estos ejemplos muestran que la capa está comprimida en un archivo .tar y cifrada, o ambos comprimidos en un archivo .tar y comprimidos en un archivo .gzip y cifrados. La siguiente captura de pantalla muestra un ejemplo de un manifiesto que se vincula a capas cifradas. También muestra un mapa de anotaciones que contiene el mensaje JWE cifrado.
Cifrado en capas usando claves simétricas
Para el cifrado simétrico con LEK, nuestro equipo eligió un cifrado que admite cifrado autenticado y se basa en el estándar de cifrado AES con claves de 128 y 256 bits.
Implementación de ejemplo: containerd
Implementamos nuestra variación en un nuevo proyecto de tiempo de ejecución de contenedor llamado containerd . Su código fuente en golang se puede ver siguiendo el enlace . El demonio de Docker usa containerd para ejecutar algunos de sus servicios, y Kubernetes tiene un complemento para usar containerd directamente. Por lo tanto, esperamos que nuestras extensiones para admitir imágenes de contenedor encriptadas sean útiles para ambos.
La implementación del cifrado multinivel utilizando LEK se encuentra en el nivel arquitectónico más bajo de extensiones. Uno de los requisitos de implementación era acomodar capas volumétricas de varios gigabytes mientras se mantenía la cantidad de memoria ocupada por el proceso que realiza la operación criptográfica en la capa con solo unos pocos megabytes de tamaño.
El soporte para algoritmos de encriptación autenticados en Golang toma una matriz de bytes como entrada y realiza la etapa completa de encriptarla (sellarla) o desencriptarla (abrirla), evitando la transferencia y adición de matrices adicionales a la secuencia. Dado que esta API de cifrado requería cargar toda la capa en la memoria o inventar algún esquema para cambiar el vector de inicialización (IV) para cada bloque, decidimos no usar el cifrado autenticado de golang con soporte de datos vinculados (AEAD). En su lugar, usamos la biblioteca criptográfica de golang maliciosa que admite AEAD en transmisiones(bloques) e implementa su propio esquema para cambiar IV en cada bloque. En nuestra implementación, dividimos la capa en bloques de 1 MB, que transferimos uno por uno para el cifrado. Este enfoque le permite reducir la cantidad de memoria cuando usa un cifrado autenticado. En el lado del descifrado, hacemos lo contrario y prestamos atención a los errores devueltos por la función Open () para asegurarnos de que los bloques de cifrado no hayan sido manipulados.
Por encima del cifrado simétrico, los esquemas criptográficos asimétricos cifran el LEK y el vector de inicialización (IV). Para agregar o eliminar esquemas criptográficos, registramos cada implementación criptográfica asimétrica. Cuando se llama a la API de código criptográfico asimétrico para cifrar la capa, llamamos a los controladores criptográficos registrados uno por uno, pasando las claves públicas de los destinatarios. Una vez que se han utilizado todas las claves de destinatario para el cifrado, volvemos al mapa de anotaciones con los identificadores de criptoalgoritmo asimétrico como claves de mapeo y los valores que contienen los mensajes codificados en OpenPGP, JWE y PKCS # 7. Cada mensaje contiene LEK y IV empaquetados. Los mapas de anotaciones se almacenan en el documento de manifiesto como se muestra en la captura de pantalla anterior.
También podemos agregar destinatarios a una imagen ya cifrada. Los autores de imágenes agregan destinatarios si están en la lista. La clave privada se utiliza para la lista de destinatarios, que se requiere para descomprimir los niveles LEK e IV. Luego empaquetamos el LEK y el IV en un nuevo mensaje usando la nueva clave de destinatario y agregamos este mensaje al mapa de anotaciones.
Hemos utilizado tres tipos de esquemas de cifrado asimétrico para diferentes tipos de claves. Usamos claves OpenPGP para cifrar mensajes OpenPGP. El PKCS # 7 que estamos usando requiere certificados x.509 para las claves de cifrado. JWE maneja todos los demás tipos de claves, como claves RSA simples, curvas elípticas y claves simétricas. Hemos creado un prototipo de extensión para JWE que permite operaciones criptográficas utilizando claves administradas por el servidor KMIP.
El tiempo de ejecución en contenedor incluye una herramienta de cliente ctr para interactuar con él. Ampliamos ctr para permitir la prueba de nuestros cambios y proporcionar acceso a los usuarios del contenedor. ctr ya implementa un subcomando que admite operaciones de imágenes, como interactuar con el registro de imágenes al obtenerlas y enviarlas.
Hemos ampliado este subcomando agregando funcionalidad para cifrar imágenes y habilitar el cifrado de capas específicas de arquitecturas específicas utilizando un conjunto específico de claves. Este enfoque permite a los usuarios cifrar solo aquellas capas que contienen datos confidenciales y dejar otras capas sin cifrar. Este último se puede deduplicar, pero esto casi no es posible para las capas cifradas.
Asimismo, podemos descifrar las capas individuales de arquitecturas individuales. Hemos agregado un subcomando layerinfo que muestra el estado de cifrado de cada capa y muestra las tecnologías de cifrado utilizadas para ello. Para OpenPGP, también podemos mostrar los ID de clave necesarios para el descifrado o convertirlos a las direcciones de correo electrónico de sus destinatarios mediante un llavero.
Además, puede exportar e importar imágenes de contenedores. Hemos implementado soporte para el cifrado de capas en la exportación y descifrado en la importación. Aunque desciframos las capas para crear el sistema de archivos rootfs del contenedor, las capas cifradas y los archivos de metadatos originales, como sus manifiestos, se conservan. Este enfoque le permite exportar una imagen cifrada y realizar comprobaciones de autorización cuando los usuarios desean iniciar un contenedor con una imagen cifrada.
Cuando se recupera una imagen simple (sin cifrar) del registro, se desempaqueta y descomprime automáticamente para que los contenedores se puedan crear a partir de ella inmediatamente. Para facilitar las imágenes cifradas, le sugerimos que pase la clave privada al equipo de desembalaje para que puedan descifrar las capas antes de desembalar. Si la imagen está cifrada con varias claves, se pueden pasar varias claves al comando de extracción. Esta transferencia también es compatible. Después de extraer correctamente la imagen cifrada del registro, cualquier persona con acceso a containerd puede crear un contenedor a partir de la imagen. Para confirmar que el usuario tiene derechos para usar la imagen del contenedor, le sugerimos que proporcione las claves privadas utilizadas para descifrar el contenedor.Usamos claves para verificar la autorización del usuario, si se pueden usar para descifrar el LEK de cada nivel cifrado, y si esto se confirma, permitimos que se inicie el contenedor.
Una guía paso a paso para el cifrado con containerd
En esta sección, demostraremos los pasos de cifrado que se aplican con contentderd usando ctr en la línea de comando. Le mostraremos cómo cifrar y descifrar una imagen de contenedor.
En primer lugar, debe clonar el repositorio git containerd / imgcrypt , que es un subproyecto y puede cifrar / descifrar la imagen del contenedor. Entonces necesitas construir un contenedor y ejecutarlo. Para completar estos pasos, necesita saber cómo está configurado el entorno de desarrollo de
golang : imgcrypt requiere la versión en contenedor 1.3 o superior.
Construya e instale imgcrypt:
# make
# sudo make install
Ejecute containerd con el archivo de configuración que se ve en el siguiente ejemplo. Para evitar conflictos en containerd, use el directorio / tmp para directorios. También compile la versión 1.3 en contenedor desde la fuente, pero no la instale.
# cat config.toml
disable_plugins = ["cri"]
root = "/tmp/var/lib/containerd"
state = "/tmp/run/containerd"
[grpc]
address = "/tmp/run/containerd/containerd.sock"
uid = 0
gid = 0
[stream_processors]
[stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
returns = "application/vnd.oci.image.layer.v1.tar+gzip"
path = "/usr/local/bin/ctd-decoder"
[stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
returns = "application/vnd.oci.image.layer.v1.tar"
path = "/usr/local/bin/ctd-decoder"
# sudo ~/src/github.com/containerd/containerd/bin/containerd -c config.toml
Cree un par de claves RSA con la herramienta de línea de comandos openssl y cifre la imagen:
# openssl genrsa --out mykey.pem
Generating RSA private key, 2048 bit long modulus (2 primes)
...............................................+++++
............................+++++
e is 65537 (0x010001)
# openssl rsa -in mykey.pem -pubout -out mypubkey.pem
writing RSA key
# sudo chmod 0666 /tmp/run/containerd/containerd.sock
# CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/containerd.sock"
# $CTR images pull --all-platforms docker.io/library/bash:latest
[...]
# $CTR images layerinfo --platform linux/amd64 docker.io/library/bash:latest
# DIGEST PLATFORM SIZE ENCRYPTION RECIPIENTS
0 sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609 linux/amd64 2789669
1 sha256:7dd01fd971d4ec7058c5636a505327b24e5fc8bd7f62816a9d518472bd9b15c0 linux/amd64 3174665
2 sha256:691cfbca522787898c8b37f063dd20e5524e7d103e1a3b298bd2e2b8da54faf5 linux/amd64 340
# $CTR images encrypt --recipient jwe:mypubkey.pem --platform linux/amd64 docker.io/library/bash:latest bash.enc:latest
Encrypting docker.io/library/bash:latest to bash.enc:latest
$ $CTR images layerinfo --platform linux/amd64 bash.enc:latest
# DIGEST PLATFORM SIZE ENCRYPTION RECIPIENTS
0 sha256:360be141b01f69b25427a9085b36ba8ad7d7a335449013fa6b32c1ecb894ab5b linux/amd64 2789669 jwe [jwe]
1 sha256:ac601e66cdd275ee0e10afead03a2722e153a60982122d2d369880ea54fe82f8 linux/amd64 3174665 jwe [jwe]
2 sha256:41e47064fd00424e328915ad2f7f716bd86ea2d0d8315edaf33ecaa6a2464530 linux/amd64 340 jwe [jwe]
Inicie su registro de imágenes local para que pueda cargar la imagen encriptada. Para recibir imágenes de contenedores cifradas, necesita las últimas versiones de registro.
# docker pull registry:latest
# docker run -d -p 5000:5000 --restart=always --name registry registry
Cargue la imagen encriptada en su registro local, extráigala usando ctr-enc y luego ejecute la imagen:
# $CTR images tag bash.enc:latest localhost:5000/bash.enc:latest
# $CTR images push localhost:5000/bash.enc:latest
# $CTR images rm localhost:5000/bash.enc:latest bash.enc:latest
# $CTR images pull localhost:5000/bash.enc:latest
# sudo $CTR run --rm localhost:5000/bash.enc:latest test echo 'Hello World!'
ctr: you are not authorized to use this image: missing private key needed for decryption
# sudo $CTR run --rm --key mykey.pem localhost:5000/bash.enc:latest test echo 'Hello World!'
Hello World!
Conclusión
Cifrar imágenes de contenedores es una buena adición a su seguridad, garantiza la confidencialidad de los datos y la integridad de las imágenes de contenedores en la ubicación de almacenamiento. La tecnología propuesta se basa en las tecnologías de encriptación RSA, curva elíptica y AES disponibles al público. Aplica claves a esquemas de cifrado de nivel superior como OpenPGP, JWE y PKCS # 7. Si sabe cómo trabajar con OpenPGP, puede cifrar las imágenes del contenedor para los destinatarios de OpenPGP utilizando sus direcciones de correo electrónico, mientras que las claves RSA simples y las curvas elípticas se utilizan para el cifrado como JWE.