É
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:
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.
Depois de iniciar o utilitário, você precisa ir para a
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.