FrameworkDemoiselle.gov.brCommunity Documentation

Capítulo 13. Funcionalidades

13.1. A Criptografia Simétrica
13.2. A Criptografica Assimétrica
13.2.1. Certificados A1
13.2.2. Certificados A3
13.3. Geração de Hash
13.3.1. Hash simples
13.3.2. Hash de arquivo

A cifragem e decifragem de dados são providas pela interface Cryptography e o componente se utiliza de uma fábrica dessa interface. Segue abaixo um exemplo ilustrativo:



public class App {
        public static void main(String[] args) {
                String frase = "conteudo original";
                Cryptography cryptography = CryptographyFactory.getInstance().factoryDefault();
                /* Geracao da chave unica */
                Key key = cryptography.generateKey();
                cryptography.setKey(key);
                /* Cifragem */
                byte[] conteudo_criptografado = cryptography.cipher(frase.getBytes());
                System.out.println(conteudo_criptografado);
                /* Decifragem */
                byte[] conteudo_descriptografado = cryptography.decipher(conteudo_criptografado);
                System.out.println(new String(conteudo_descriptografado));
        }
}

Os métodos cipher e decipher recebem como entrada um array de bytes e retornam o array de bytes processado.

Para que a criptografia simétrica seja realizada é necessário o uso de uma única chave, para criptografar e descriptografar. Neste caso, é necessário gerar a chave através do método generateKey.

Caso não seja informado o algoritmo de criptografia o componente utilizará como padrão o algoritmo AES (Advanced Encryption Standard). Caso necessite utilizar outro algoritmo invoque o método setAlgorithm informando um SymmetricAlgorithmEnum ou um AsymmetricAlgorithmEnum.



public class App {
        public static void main(String[] args) {
                String frase = "conteudo original";
                Cryptography cryptography = CryptographyFactory.getInstance().factoryDefault();
                /* Alterando algoritmo */
                cryptography.setAlgorithm(SymmetricAlgorithmEnum.TRI_DES);
                /* Geracao da chave unica */
                Key key = cryptography.generateKey();
                cryptography.setKey(key);
                byte[] conteudo_criptografado = cryptography.cipher(frase.getBytes());
                System.out.println(conteudo_criptografado);
                byte[] conteudo_descriptografado = cryptography.decipher(conteudo_criptografado);
                System.out.println(new String(conteudo_descriptografado));
        }
}

Caso as opções de criptografia definidas pelo SymmetricAlgorithmEnum não atendam é possível customizar os parâmetros de criptografia através dos métodos setAlgorithm, setKeyAlgorithm e setSize.



public static void main(String[] args) {
                String frase = "conteudo original";
                Cryptography cryptography = CryptographyFactory.getInstance().factoryDefault();
                /* Customizacao de parametros */
                cryptography.setAlgorithm("AES/ECB/PKCS5Padding");
                cryptography.setKeyAlgorithm("AES");
                cryptography.setSize(128);
                /* Cifragem */
                byte[] conteudo_criptografado = cryptography.cipher(frase.getBytes());
                System.out.println(conteudo_criptografado);
                /* Decifragem */
                byte[] conteudo_descriptografado = cryptography.decipher(conteudo_criptografado);
                System.out.println(new String(conteudo_descriptografado));
        }

Na criptografia assimétrica é necessário um par de chaves para realizar a cifragem e decifram das mensagens. A primeira chave é denominada chave privada e é de posse exclusiva de seu detentor. A segunda chave do par é denominada de chave pública e pode ser enviada a qualquer indivíduo.



        /* Cifragem */
        Cryptography crypto = CryptographyFactory.getInstance().factoryDefault();
        crypto.setKey(privateKey);
        byte[] conteudoCriptografado = crypto.cipher("SERPRO".getBytes());
        System.out.println(conteudoCriptografado);
        /* Decifragem */
        Cryptography crypto2 = CryptographyFactory.getInstance().factoryDefault();
        crypto2.setKey(publicKey);
        byte[] conteudoDescriptografado = crypto2.decipher(conteudoCriptografado);
        System.out.println(new String(conteudoDescriptografado));

Perceba a utilização do método setKey para informar qual chave será utilizada no processo de cifragem e decifragem. Vale lembrar que na criptografia assimétrica a cifragem realizada com a chave privada só poderá ser decifrada com a chave pública e vice-versa.

Na sequência, demonstramos a utilização do componente com certificados digitais do tipo A1 e A3.

O certificado A1 é aquele que encontra-se armazenado no sistema de arquivo do sistema operacional. Para exemplificar sua manipulação, segue o código abaixo:



        public static void main(String[] args) {
                try {
                        /* Obtendo a chave publica */
                        File file = new File("/home/{usuario}/public.der");
                        byte[] encodedPublicKey = new byte[(int) file.length()];
                        InputStream inputStreamPublicKey = new FileInputStream(file);
                        inputStreamPublicKey.read(encodedPublicKey);
                        inputStreamPublicKey.close();
                        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
                        KeyFactory kf = KeyFactory.getInstance("RSA");
                        PublicKey publicKey = kf.generatePublic(publicKeySpec);
                        /* Obtendo a chave privada */
                        file = new File("/home/{usuario}/private.pk8");
                        byte[] encodedPrivateKey = new byte[(int) file.length()];
                        InputStream inputStreamPrivateKey = new FileInputStream(file);
                        inputStreamPrivateKey.read(encodedPrivateKey);
                        inputStreamPrivateKey.close();
                        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
                        kf = KeyFactory.getInstance("RSA");
                        PrivateKey privateKey = kf.generatePrivate(privateKeySpec);
                        /* Cifragem */
                        Cryptography cripto = CryptographyFactory.getInstance().factoryDefault();
                        crypto.setAlgorithm(AsymmetricAlgorithmEnum.RSA);
                        crypto.setKey(privateKey);
                        byte[] conteudoCriptografado = crypto.cipher("SERPRO".getBytes());
                        System.out.println(conteudoCriptografado);
                        /* Decifragem */
                        Cryptography cripto2 = CryptographyFactory.getInstance().factoryDefault();
                        crypto2.setAlgorithm(AsymmetricAlgorithmEnum.RSA);
                        crypto2.setKey(publicKey);
                        byte[] conteudoDescriptografado = crypto2.decipher(conteudoCriptografado);
                        System.out.println(new String(conteudoDescriptografado));
                } catch (Exception e) {
                        e.printStackTrace();
                        Assert.assertTrue("Configuracao nao carregada: " + e.getMessage(), false);
                }
        }

Neste exemplo é demonstrada a obtenção das chaves pública e privada do certificado A1. Note que, apesar do código para manipulação dos certificados, a forma de uso do componente Demoiselle Cryptography para cifragem e decifragem de mensagens é a mesma.

O certificado A3 é armazenado em dispositivos eletrônicos como smart card ou tokens usb que criptografam o certificado provendo maior segurança. No exemplo abaixo utilizamos o componente Demoiselle Core para obtenção do keyStore a partir de um token usb. Você pode ver mais sobre esse componente em Capítulo 1, Configuração do Signer-Core



        public static void main(String[] args) {
                /* Senha do dispositivo */
                String PIN = "senha_do_token";
                try {
                        /* Obtendo a chave privada */
                        KeyStore keyStore = KeyStoreLoaderFactory.factoryKeyStoreLoader().getKeyStore(PIN);
                        String alias = (String) keyStore.aliases().nextElement();
                        PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, PIN.toCharArray());
                        /* Obtendo a chave publica */
                        CertificateLoader cl = new CertificateLoaderImpl();
                        X509Certificate x509 = cl.loadFromToken(PIN);
                        PublicKey publicKey = x509.getPublicKey();
                        /*Configurando o Criptography */
                        Cryptography crypto = CryptographyFactory.getInstance().factoryDefault();
                        crypto.setAlgorithm(AsymmetricAlgorithmEnum.RSA);
                        crypto.setProvider(keyStore.getProvider());
                        /* criptografando com a chave privada */
                        crypto.setKey(privateKey);
                        byte[] conteudoCriptografado = crypto.cipher("SERPRO".getBytes());
                        System.out.println(conteudoCriptografado);
                        /* descriptografando com a chave publica */
                        crypto.setKey(publicKey);
                        byte[] conteudoAberto = crypto.decipher(conteudoCriptografado);
                        System.out.println(new String(conteudoAberto));
                } catch (UnrecoverableKeyException e) {
                        e.printStackTrace();
                } catch (KeyStoreException e) {
                        e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                        e.printStackTrace();
                }
        }

O componente utiliza como padrão o provider SUN JCE, mas caso necessite de outro provider utilize o método setProvider da classe Cryptography.

No exemplo acima foi utilizado o método setProvider para informar o provedor, ou seja, quem executará os algoritmos de criptografia. Até então, nos exemplos anteriores, o provedor era a biblioteca SUN JCE contida na própria JVM. Como o token é o único a ter acesso a chave privada do certificado ele também será o único capaz de executar os processos de cifragem e decifragem.

Desta forma foi utilizado o objeto KeyStore do próprio token usb para informar o novo provider ao Cryptography.