Suporte para tokens PKCS # 11 com criptografia GOST em Python. Parte III - O invólucro PyKCS11

imagemÉ hora de contar como o suporte para criptografia russa foi adicionado ao projeto PyKCS11 . Tudo começou quando me deparei com uma correspondência entre o desenvolvedor do projeto PyKCS11 e consumidores em potencial sobre o possível suporte dos algoritmos GOST R 34.10-2012 nele. Nesta correspondência, o autor do PkCS11 disse que não incluirá suporte para criptoalgoritmos russos até que sejam padronizados.

Ele expressou a mesma ideia para mim quando eu pedi a ele para fazer isso. E não apenas para fazer isso, mas enviar o código do programa apropriado:



imagem



Depois disso, considerei a possibilidade de bifurcar o código em meu repositório e fazer as edições apropriadas nele. O projeto PyKCS11 com suporte à criptografia russa está aqui .



I. Adicionando suporte para criptoalgoritmos russos



Então, o que foi feito. Na verdade, segui uma das dicas do autor do projeto PyKCS11:

O que posso propor a você é a criação de um arquivo PyKCS11_GOST.py com os nomes de constantes e funções que você deseja para estender PyKCS11 com suporte GOST.

(Eu posso sugerir que você crie um arquivo PyKCS11_GOST.py com os nomes das constantes e funções que você deseja estender PyKCS11 para suportar GOST.)



Todas as constantes aprovadas pelo TC-26 para PKCS # 11 foram consolidadas em um arquivo pkcs11t_gost.h, colocado na pasta 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 inclui mecanismos necessários para a formação e verificação de assinaturas de acordo com (GOST R 34.10-2012) GOST R 34.10-2012, e criptografia (GOST R 34.12-2015 e GOST R 34.13-2015 - algoritmos de criptografia Grasshopper e Magma) . Naturalmente, os algoritmos de hash GOST R 34.11-2012 também estão presentes aqui.

Para que as constantes GOST sejam incluídas no processo de construção do módulo, é necessário adicionar uma instrução de inclusão ao arquivo pkcs11t_gost.h ao arquivo pkcs11.i (arquivo para SWIG)

%include "pkcs11t_gost.h"
      
      





na frente do operador

%include "pkcs11lib.h"
      
      





Mas isso não é tudo. No método getMechanismList (script PKCS11 / __ init__.py), a saída de mecanismos cujo código é maior que CKM_VENDOR_DEFINED é bloqueada (é exatamente sobre isso que o autor do projeto PyKCS11 escreve) (0x80000000L). Observe que as constantes GOST para novos algoritmos se enquadram nesta restrição. É necessário removê-lo pelo menos para GOSTs, então vamos substituir o código do método getMechanismList por um novo:

    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
      
      







Observe também que, embora o módulo inclua todos os mecanismos definidos nos arquivos de inclusão pkcs11t.h e pkcs11t_gost.h para pkcs11 v.2.40, nem todos esses mecanismos podem ser implementados. O problema é que alguns deles requerem uma estrutura de parâmetros específica. Isso se aplica em particular ao mecanismo CKM_RSA_PKCS_OAEP, que requer parâmetros na forma de uma estrutura CK_RSA_PKCS_OAEP_PARAMS, e ao mecanismo CKM_PKCS5_PBKD2, que espera parâmetros na forma de uma estrutura CK_PKCS5_PBKD2_PARAMS. Existem outros mecanismos também. Mas, uma vez que o autor implementou estruturas separadas para mecanismos separados (para o mesmo CKM_RSA_PKCS_OAEP), não será difícil implementar suporte para estruturas de parâmetros para outros mecanismos. Então, se alguém precisa trabalhar com um contêiner PKCS # 12,então você terá que implementar suporte para a estrutura CK_PKCS5_PBKD2_PARAMS.

Tudo isso se refere a mecanismos criptográficos bastante complexos.

Mas tudo que diz respeito a hashing, formação de verificação de assinatura eletrônica e, por fim, criptografia, tudo funciona muito bem. Mas primeiro você precisa montar um projeto.



II. Construindo um wrapper PyKCS11 com suporte GOST



Não é diferente de construir o wrapper PkCS11 nativo, exceto que você precisa obter o código-fonte aqui .

Em seguida, siga as instruções para construir e instalar o pacote PyKCS11.

O teste requer um token com suporte para criptografia russa. Aqui, queremos dizer GOST R 34.10-2012 e GOST R 34.11-2012. Pode ser um token de hardware, por exemplo RuTokenECP-2.0, ou tokens de software ou nuvem.

Você pode instalar um token de software ou acessar um token de nuvem usando o utilitário cryptoarmpkcs.

Você pode baixar o utilitário cryptoarmpkcs aqui.




Depois de iniciar o utilitário, você precisa ir para a



imagem



guia "Criar tokens": Na guia você pode encontrar instruções para obter e instalar tokens.



III. Testando algoritmos russos



Para teste, você pode usar os scripts que estão na pasta testGost:

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


Para o teste, os dados iniciais foram obtidos dos GOSTs correspondentes e das recomendações do TK-26.

Os seguintes mecanismos são testados nesses scripts:

1. Geração de pares de chaves:

  • CKM_GOSTR3410_512_KEY_PAIR_GEN (GOST R 34.10-2012 com um comprimento de chave de 1024 bits)
  • CKM_GOSTR3410_KEY_PAIR_GEN (GOST R 34.10-2012 com comprimento de chave de 512 bits)


2. Formação e verificação de uma assinatura eletrônica:

  • CKM_GOSTR3410
  • CKM_GOSTR3410_512
  • CKM_GOSTR3410_WITH_GOSTR3411_12_256


3. Hashing:

  • CKM_GOSTR3411_12_256


4. Criptografia / descriptografia

  • CKM_KUZNYECHIK_CBC




A geração de pares de chaves permite ao detentor do token obter uma chave privada com a qual ele pode assinar, por exemplo, uma solicitação de certificado. Uma solicitação de certificado pode ser enviada a um centro de certificação e um certificado pode ser emitido lá. O proprietário do certificado pode importá-lo para o token onde a chave privada está armazenada. O proprietário do token agora tem um certificado pessoal com uma chave privada que pode usar para assinar documentos.

Bem, se ele precisa de um modo de segurança especial, ele pode criptografar o documento usando um dos algoritmos, ou seja, Magma ou Grasshopper. Tudo isso, é claro, se o próprio token suportar esses mecanismos, o pacote PyKCS11 será apenas um intermediário.

Isso conclui nossa história relacionada ao suporte de tokens com criptografia russa em Python.



All Articles