Soporte para tokens PKCS # 11 con criptografía GOST en Python. Parte III - La envoltura PyKCS11

imagenEs hora de contarle cómo se agregó la compatibilidad con la criptografía rusa al proyecto PyKCS11 . Todo comenzó cuando encontré una correspondencia entre el desarrollador del proyecto PyKCS11 y los consumidores potenciales sobre el posible soporte de los algoritmos GOST R 34.10-2012 en él. En esta correspondencia, el autor de PkCS11 dijo que no va a incluir soporte para criptoalgoritmos rusos hasta que estén estandarizados.

Me expresó la misma idea cuando le pedí que lo hiciera. Y no solo para hacerlo, sino que envió el código de programa correspondiente:



imagen



Después de eso, consideré posible bifurcar el código en mi repositorio y realizar las ediciones adecuadas. El proyecto PyKCS11 con soporte de criptografía rusa está aquí .



I. Adición de soporte para criptoalgoritmos rusos



Entonces, ¿qué se ha hecho? De hecho, seguí uno de los consejos del autor del proyecto PyKCS11:

Lo que puedo proponerle es crear un archivo PyKCS11_GOST.py con los nombres y funciones constantes que desee para extender PyKCS11 con soporte GOST.

(Podría sugerirle que cree un archivo PyKCS11_GOST.py con los nombres de las constantes y funciones que desea extender PyKCS11 para admitir GOST).



Todas las constantes aprobadas por TC-26 para PKCS # 11 se han consolidado en un archivo pkcs11t_gost.h, ubicado en la carpeta src:

//-26
#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xd4321000 
#define NSSCK_VENDOR_PKSC11_RU_TEAM NSSCK_VENDOR_PKCS11_RU_TEAM
#define CK_VENDOR_PKCS11_RU_TEAM_TC26 NSSCK_VENDOR_PKCS11_RU_TEAM
#define CKK_GOSTR3410_512 	0xd4321003UL
#define CKK_KUZNYECHIK 		0xd4321004UL
#define CKK_MAGMA 		0xd4321005UL
#define CKK_GOSTR3410_256 	0xd4321006UL
#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411_TC26_V1 	0xd4321801UL
#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411_2012_256 0xd4321002UL
#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411_2012_512 0xd4321003UL
#define CKM_GOSTR3410_512_KEY_PAIR_GEN		0xd4321005UL
#define CKM_GOSTR3410_512			0xd4321006UL
#define CKM_GOSTR3410_WITH_GOSTR3411		0x00001202
#define CKM_GOSTR3410_WITH_GOSTR3411_12_256	0xd4321008UL
#define CKM_GOSTR3410_WITH_GOSTR3411_12_512	0xd4321009UL
#define CKM_GOSTR3410_12_DERIVE			0xd4321007UL
#define CKM_GOSR3410_2012_VKO_256		0xd4321045UL
#define CKM_GOSR3410_2012_VKO_512		0xd4321046UL
#define CKM_KDF_4357				0xd4321025UL
#define CKM_KDF_GOSTR3411_2012_256		0xd4321026UL
#define CKM_KDF_TREE_GOSTR3411_2012_256		0xd4321044UL
#define CKM_GOSTR3410_PUBLIC_KEY_DERIVE		0xd432100AUL
#define CKM_LISSI_GOSTR3410_PUBLIC_KEY_DERIVE	0xd4321037UL
#define CKM_GOST_GENERIC_SECRET_KEY_GEN		0xd4321049UL
#define CKM_GOST_CIPHER_KEY_GEN			0xd4321048UL
#define CKM_GOST_CIPHER_ECB			0xd4321050UL
#define CKM_GOST_CIPHER_CBC			0xd4321051UL
#define CKM_GOST_CIPHER_CTR			0xd4321052UL
#define CKM_GOST_CIPHER_OFB			0xd4321053UL
#define CKM_GOST_CIPHER_CFB			0xd4321054UL
#define CKM_GOST_CIPHER_OMAC			0xd4321055UL
#define CKM_GOST_CIPHER_KEY_WRAP		0xd4321059UL
#define CKM_GOST_CIPHER_ACPKM_CTR		0xd4321057UL
#define CKM_GOST_CIPHER_ACPKM_OMAC		0xd4321058UL
#define CKM_GOST28147_PKCS8_KEY_WRAP		0xd4321036UL
#define CKM_GOST_CIPHER_PKCS8_KEY_WRAP		0xd432105AUL
#define CKM_GOST28147_CNT			0xd4321825UL
#define CKM_KUZNYECHIK_KEY_GEN			0xd4321019UL
#define CKM_KUZNYECHIK_ECB			0xd432101AUL
#define CKM_KUZNYECHIK_CBC			0xd432101EUL
#define CKM_KUZNYECHIK_CTR			0xd432101BUL
#define CKM_KUZNYECHIK_OFB			0xd432101DUL
#define CKM_KUZNYECHIK_CFB			0xd432101CUL
#define CKM_KUZNYECHIK_OMAC			0xd432101FUL
#define CKM_KUZNYECHIK_KEY_WRAP			0xd4321028UL
#define CKM_KUZNYECHIK_ACPKM_CTR		0xd4321042UL
#define CKM_KUZNYECHIK_ACPKM_OMAC		0xd4321043UL
#define CKM_MAGMA_KEY_GEN			0xd432102AUL
#define CKM_MAGMA_ECB				0xd4321018UL
#define CKM_MAGMA_CBC				0xd4321023UL
#define CKM_MAGMA_CTR				0xd4321020UL
#define CKM_MAGMA_OFB				0xd4321022UL
#define CKM_MAGMA_CFB				0xd4321021UL
#define CKM_MAGMA_OMAC				0xd4321024UL
#define CKM_MAGMA_KEY_WRAP			0xd4321029UL
#define CKM_MAGMA_ACPKM_CTR			0xd4321040UL
#define CKM_MAGMA_ACPKM_OMAC			0xd4321041UL
#define CKM_GOSTR3411_12_256			0xd4321012UL
#define CKM_GOSTR3411_12_512			0xd4321013UL
#define CKM_GOSTR3411_12_256_HMAC		0xd4321014UL
#define CKM_GOSTR3411_12_512_HMAC		0xd4321015UL
#define CKM_PBA_GOSTR3411_WITH_GOSTR3411_HMAC	0xd4321035UL
#define CKM_TLS_GOST_KEY_AND_MAC_DERIVE		0xd4321033UL
#define CKM_TLS_GOST_PRE_MASTER_KEY_GEN		0xd4321031UL
#define CKM_TLS_GOST_MASTER_KEY_DERIVE		0xd4321032UL
#define CKM_TLS_GOST_PRF			0xd4321030UL
#define CKM_TLS_GOST_PRF_2012_256		0xd4321016UL
#define CKM_TLS_GOST_PRF_2012_512		0xd4321017UL
#define CKM_TLS_TREE_GOSTR3411_2012_256		0xd4321047UL
      
      





Esta lista incluye los mecanismos necesarios para la formación y verificación de firmas de acuerdo con (GOST R 34.10-2012) GOST R 34.10-2012 y cifrado (GOST R 34.12-2015 y GOST R 34.13-2015 - algoritmos de cifrado Grasshopper y Magma) . Naturalmente, los algoritmos hash GOST R 34.11-2012 también están presentes aquí.

Para que las constantes GOST se incluyan en el proceso de construcción del módulo, es necesario agregar una declaración de inclusión al archivo pkcs11t_gost.h al archivo pkcs11.i (archivo para SWIG)

%include "pkcs11t_gost.h"
      
      





delante del operador

%include "pkcs11lib.h"
      
      





Pero eso no es todo. En el método getMechanismList (script PKCS11 / __ init__.py), se bloquea la salida de los mecanismos cuyo código es mayor que CKM_VENDOR_DEFINED (esto es exactamente sobre lo que escribe el autor del proyecto PyKCS11) (0x80000000L). Tenga en cuenta que las constantes GOST para nuevos algoritmos caen bajo esta restricción. Es necesario eliminarlo al menos para GOST, por lo que reemplazaremos el código del método getMechanismList por uno nuevo:

    def getMechanismList(self, slot):
        """
        C_GetMechanismList

        :param slot: slot number returned by :func:`getSlotList`
        :type slot: integer
        :return: the list of available mechanisms for a slot
        :rtype: list
        """
        mechanismList = PyKCS11.LowLevel.ckintlist()
        rv = self.lib.C_GetMechanismList(slot, mechanismList)
        if rv != CKR_OK:
            raise PyKCS11Error(rv)
        m = []
#  
#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xd4321000 
        for x in range(len(mechanismList)):
            mechanism = mechanismList[x]
            if mechanism >= CKM_VENDOR_DEFINED:
                if mechanism >= CKM_VENDOR_DEFINED and mechanism < 0xd4321000:
                    k = 'CKM_VENDOR_DEFINED_0x%X' % (mechanism - CKM_VENDOR_DEFINED)
                    CKM[k] = mechanism
                    CKM[mechanism] = k
            m.append(CKM[mechanism])
        return m
#ORIGINAL
#        for x in range(len(mechanismList)):
#            mechanism = mechanismList[x]
#            if mechanism >= CKM_VENDOR_DEFINED:
#                k = 'CKM_VENDOR_DEFINED_0x%X' % (mechanism - CKM_VENDOR_DEFINED)
#                CKM[k] = mechanism
#                CKM[mechanism] = k
#            m.append(CKM[mechanism])
#        return m
      
      







Tenga en cuenta también que, aunque el módulo incluye todos los mecanismos que se definen en los archivos de inclusión pkcs11t.hy pkcs11t_gost.h para pkcs11 v.2.40, no todos estos mecanismos se pueden implementar. El problema es que algunos de ellos requieren una estructura de parámetros específica. Esto se aplica en particular al mecanismo CKM_RSA_PKCS_OAEP, que requiere parámetros en forma de estructura CK_RSA_PKCS_OAEP_PARAMS, y al mecanismo CKM_PKCS5_PBKD2, que espera parámetros en forma de estructura CK_PKCS5_PBSKD2_PARAM. También existen otros mecanismos. Pero dado que el autor ha implementado estructuras separadas para mecanismos separados (para el mismo CKM_RSA_PKCS_OAEP), no será difícil implementar soporte para estructuras de parámetros para otros mecanismos. Entonces, si alguien necesita trabajar con un contenedor PKCS # 12,entonces deberá implementar el soporte para la estructura CK_PKCS5_PBKD2_PARAMS.

Todo esto se refiere a mecanismos criptográficos bastante complejos.

Pero todo lo que se refiere al hash, la formación de verificación de una firma electrónica y, finalmente, el cifrado, todo funciona muy bien. Pero primero necesitas armar un proyecto.



II. Construyendo un contenedor PyKCS11 con soporte GOST



No es diferente de construir el contenedor nativo PkCS11, excepto que necesita obtener el código fuente aquí .

A continuación, siga las instrucciones para compilar e instalar el paquete PyKCS11.

Las pruebas requieren un token con soporte de criptografía rusa. Aquí nos referimos a GOST R 34.10-2012 y GOST R 34.11-2012. Puede ser un token de hardware, por ejemplo, RuTokenECP-2.0, o tokens de software o en la nube.

Puede instalar un token de software o acceder a un token en la nube mediante la utilidad cryptoarmpkcs.

Puede descargar la utilidad cryptoarmpkcs aquí.




Después de iniciar la utilidad, debe ir a la



imagen



pestaña "Crear tokens": en la pestaña puede encontrar instrucciones para obtener e instalar tokens.



III. Probando algoritmos rusos



Para realizar pruebas, puede utilizar los scripts que se encuentran en la carpeta testGost:

  • ckm_kuznyechik_cbc.py
  • ckm_gostr3411_12_256.py
  • ckm_gostr3410_with_gostr3411_12_256.py
  • ckm_gostr3410_512.py


Para las pruebas, los datos iniciales se tomaron tanto de los GOST correspondientes como de las recomendaciones de TK-26.

Los siguientes mecanismos se prueban en estos scripts:

1. Generación de pares de claves:

  • CKM_GOSTR3410_512_KEY_PAIR_GEN (GOST R 34.10-2012 con una longitud de clave de 1024 bits)
  • CKM_GOSTR3410_KEY_PAIR_GEN (GOST R 34.10-2012 con longitud de clave de 512 bits)


2. Formación y verificación de una firma electrónica:

  • CKM_GOSTR3410
  • CKM_GOSTR3410_512
  • CKM_GOSTR3410_WITH_GOSTR3411_12_256


3. Hashing:

  • CKM_GOSTR3411_12_256


4. Cifrado / descifrado

  • CKM_KUZNYECHIK_CBC




La generación de pares de claves permite al titular del token obtener una clave privada con la que puede firmar, por ejemplo, una solicitud de certificado. Se puede enviar una solicitud de certificado a un centro de certificación y allí se puede emitir un certificado. El propietario del certificado puede importarlo al token donde se almacena la clave privada. El propietario del token ahora tiene un certificado personal con una clave privada que puede usar para firmar documentos.

Bueno, si necesita un modo de seguridad especial, entonces puede cifrar el documento usando uno de los algoritmos, a saber, Magma o Grasshopper. Todo esto, por supuesto, si el token en sí admite estos mecanismos, el paquete PyKCS11 es solo un intermediario.

Con esto concluye nuestra historia relacionada con el soporte de tokens con criptografía rusa en Python.



All Articles