Implementação de Criptografia SM2, SM3 e SM4 com BouncyCastle em Java

Este guia aborda a utilização da biblioteca BouncyCastle para implementar algoritmos criptográficos nacionais, incluindo SM2, SM3 e SM4, em um ambiente Java. O foco está na prática de geração de chaves, criptografia e descriptografia.

Objetivos da Prática

  • Executar as tarefas em um sistema operacional como openEuler (recomendado), Ubuntu ou Windows (menos recomendado).
  • Implementar a criptografia e descriptografia com base no algoritmo SM2, documentando os resultados através de capturas de tela.
  • Integrar os algoritmos SM3 e SM4 no processo, fornecendo o código-fonte e evidências de execução como parte opcional da atividade.

Implementação Técnica

Para começar, certifique-se de que a dependência do BouncyCastle está configurada no seu projeto. A seguir, estão os exemplos de código reescritos com estrutura e nomenclatura alteradas, mantendo a funcionalidade original.

Código Principal de Demonstração

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;

public class AplicacaoCriptografica {
    private static final String MENSAGEM_ORIGINAL = "texto_exemplo_123";

    public static void main(String[] args) throws Exception {
        SM2Criptografia sm2Helper = new SM2Criptografia();
        final ECGenParameterSpec parametrosSM2 = new ECGenParameterSpec("sm2p256v1");
        final KeyPairGenerator geradorParChaves = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        geradorParChaves.initialize(parametrosSM2);
        KeyPair parDeChaves = geradorParChaves.generateKeyPair();
        PublicKey chavePublica = parDeChaves.getPublic();
        PublicKey chavePrivada = parDeChaves.getPrivate();
        
        String dadosCriptografados = sm2Helper.criptografar(chavePublica, MENSAGEM_ORIGINAL);
        System.out.println("Dados criptografados (hex): " + dadosCriptografados);
        String textoDescriptografado = sm2Helper.descriptografar(chavePrivada, dadosCriptografados);
        System.out.println("Texto descriptografado: " + textoDescriptografado);

        SM3Hash sm3Hasher = new SM3Hash();
        byte[] resumo = sm3Hasher.calcularHash(MENSAGEM_ORIGINAL);
        System.out.println("Hash SM3: " + Arrays.toString(resumo));

        SM4Cifra sm4Cifra = new SM4Cifra();
        byte[] chaveSM4 = SM4GeradorChave.criarChave();
        byte[] vetorInicializacao = null;
        byte[] dadosSM4Criptografados = sm4Cifra.encriptar(resumo, chaveSM4, ModoPreenchimentoSM4.ECB_SEM_PREENCHIMENTO, vetorInicializacao);
        System.out.println("Dados SM4 criptografados: " + Arrays.toString(dadosSM4Criptografados));
        byte[] dadosSM4Descriptografados = sm4Cifra.decriptar(dadosSM4Criptografados, chaveSM4, ModoPreenchimentoSM4.ECB_SEM_PREENCHIMENTO, vetorInicializacao);
        System.out.println("Dados SM4 descriptografados: " + Arrays.toString(dadosSM4Descriptografados));
    }
}

Utilitário para SM2

import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.util.encoders.Hex;

import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;

public class SM2Criptografia {
    public String criptografar(PublicKey chavePublica, String dados) {
        ECPublicKeyParameters parametrosChavePublica = extrairParametrosPublicos(chavePublica);
        SM2Engine motorSM2 = new SM2Engine();
        motorSM2.init(true, new ParametersWithRandom(parametrosChavePublica, new SecureRandom()));

        byte[] bytesSaida = null;
        try {
            byte[] bytesEntrada = dados.getBytes(StandardCharsets.UTF_8);
            bytesSaida = motorSM2.processBlock(bytesEntrada, 0, bytesEntrada.length);
        } catch (Exception e) {
            throw new RuntimeException("Erro durante a criptografia SM2", e);
        }
        return Hex.toHexString(bytesSaida);
    }

    public String descriptografar(PrivateKey chavePrivada, String dadosCriptografados) {
        byte[] bytesCriptografados = Hex.decode(dadosCriptografados);
        ECPrivateKeyParameters parametrosChavePrivada = extrairParametrosPrivados(chavePrivada);
        SM2Engine motorSM2 = new SM2Engine();
        motorSM2.init(false, parametrosChavePrivada);

        try {
            byte[] bytesResultado = motorSM2.processBlock(bytesCriptografados, 0, bytesCriptografados.length);
            return new String(bytesResultado, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("Erro durante a descriptografia SM2", e);
        }
    }

    private ECPublicKeyParameters extrairParametrosPublicos(PublicKey chave) {
        BCECPublicKey chaveBCEC = (BCECPublicKey) chave;
        ECParameterSpec specParametros = chaveBCEC.getParameters();
        ECDomainParameters dominioParametros = new ECDomainParameters(
            specParametros.getCurve(), specParametros.getG(), specParametros.getN()
        );
        return new ECPublicKeyParameters(chaveBCEC.getQ(), dominioParametros);
    }

    private ECPrivateKeyParameters extrairParametrosPrivados(PrivateKey chave) {
        BCECPrivateKey chaveBCEC = (BCECPrivateKey) chave;
        ECParameterSpec specParametros = chaveBCEC.getParameters();
        ECDomainParameters dominioParametros = new ECDomainParameters(
            specParametros.getCurve(), specParametros.getG(), specParametros.getN()
        );
        return new ECPrivateKeyParameters(chaveBCEC.getD(), dominioParametros);
    }
}

Utilitário para SM3

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Security;

public class SM3Hash {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public byte[] calcularHash(String entrada) {
        SM3Digest digestSM3 = new SM3Digest();
        byte[] dadosEntrada = entrada.getBytes();
        digestSM3.update(dadosEntrada, 0, dadosEntrada.length);
        byte[] hashResultado = new byte[digestSM3.getDigestSize()];
        digestSM3.doFinal(hashResultado, 0);
        return hashResultado;
    }
}

Geração de Chaves para SM4

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.KeyGenerator;
import java.security.SecureRandom;
import java.security.Security;

public class SM4GeradorChave {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static byte[] criarChave() throws Exception {
        KeyGenerator gerador = KeyGenerator.getInstance("SM4", BouncyCastleProvider.PROVIDER_NAME);
        gerador.init(128, new SecureRandom());
        return gerador.generateKey().getEncoded();
    }
}

Enumeração para Modos e Preenchimentos do SM4

public enum ModoPreenchimentoSM4 {
    ECB_SEM_PREENCHIMENTO("SM4/ECB/NoPadding"),
    ECB_PKCS5("SM4/ECB/PKCS5Padding"),
    ECB_PKCS7("SM4/ECB/PKCS7Padding"),
    CBC_SEM_PREENCHIMENTO("SM4/CBC/NoPadding"),
    CBC_PKCS5("SM4/CBC/PKCS5Padding"),
    CBC_PKCS7("SM4/CBC/PKCS7Padding");

    private final String nomeAlgoritmo;

    ModoPreenchimentoSM4(String nome) {
        this.nomeAlgoritmo = nome;
    }

    public String obterNome() {
        return nomeAlgoritmo;
    }
}

Utilitário para SM4

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;

public class SM4Cifra {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public byte[] encriptar(byte[] dados, byte[] chave, ModoPreenchimentoSM4 modo, byte[] iv) throws Exception {
        return processarDados(dados, chave, modo, iv, Cipher.ENCRYPT_MODE);
    }

    public byte[] decriptar(byte[] dadosCriptografados, byte[] chave, ModoPreenchimentoSM4 modo, byte[] iv) throws Exception {
        return processarDados(dadosCriptografados, chave, modo, iv, Cipher.DECRYPT_MODE);
    }

    private byte[] processarDados(byte[] entrada, byte[] chave, ModoPreenchimentoSM4 modo, byte[] iv, int operacao) throws Exception {
        IvParameterSpec especVetor = iv != null ? new IvParameterSpec(iv) : null;
        SecretKeySpec chaveSecreta = new SecretKeySpec(chave, "SM4");
        Cipher cifra = Cipher.getInstance(modo.obterNome(), BouncyCastleProvider.PROVIDER_NAME);
        if (especVetor == null) {
            cifra.init(operacao, chaveSecreta);
        } else {
            cifra.init(operacao, chaveSecreta, especVetor);
        }
        return cifra.doFinal(entrada);
    }
}

Tags: bouncycastle SM2 SM3 SM4 java

Publicado em 6-15 05:20 por Thomas