Hospedagem Profissional

Hospedagem Profissional
Clique aqui e ganhe US$ 10,00 para testar durante 1 mês a melhor hospedagem: Digital Ocean!

quarta-feira, 22 de outubro de 2008

Trabalhando com encriptação e assinatura digital

Quer segurança nos seus dados? Então leia este artigo.


 Download do material relacionado ao tutorial



Trabalhando com encriptação e assinatura digital


Hoje em dia, na grande maioria das empresas, uma grande preocupação é questão com a segurança dos dados. Por se tratarem de dados importantíssimos para as companhias e seus clientes, é de fundamental importância garantir que eles estejam seguros e protegidos. Afinal, imagine a sua senha de acesso do Submarino sendo roubada? Seria um grande prejuízo para você e a empresa. 

A solução de parte desses problemas de segurança pode ser resolvida com a encriptação dos dados trafegados na rede, por meio de algorítmos de assinatura, com o DSA e RSA, além do uso de certificados digitais. 

Os certificados digitais são comumente usados para assinar os JARs dos Applets, para que eles possam ter acesso à máquina do cliente, ou mesmo em sites seguros, que trafegam dados como senhas, cartão de banco e etc. Estes certificados podem ter certificados conhecidos, fornecidos por grandes empresas de segurança, como a Thawte e a VeriSign, porém não há a necessidade, pois geralmente esses certificados são um pouco caros. 

Há pouco tempo eu tive um certo esforço para trabalhar com encriptação de dados e assinatura digital, para acessar um web services. Para resolver todo este problema eu utilizei um certificado digital, criado por mim mesmo e código Java para extração das chaves e geração da assinatura dos dados. 

Gerando o Certificado Digital 

Inicialmente precisamos ter um certificado digital, que será a base para encriptarmos e decriptarmos os dados. Esse certificado vai conter uma chave pública e privada. A privada é usada por você, para encriptar os dados. A chave pública você fornece para quem for decriptar os seus dados. 

No meu caso, eu assinava os dados de acesso ao Web service com a minha chave privada. O meu fornecedor do Web Service tinha uma cópia da minha chave pública, para que ele pudesse decriptar os dados que eu envei, e ele pudesse se certificar da minha autenticidade. 

O próprio JDK do Java fornece uma ferramente para gerar um certificado digital, o keytool. Não vamos explorar muito em detalhes esta ferramenta, mas vamos sim ver como gerar um simples certificado digital, que é a nossa intenção. 

A ferramente keytool recebe alguns argumentos na sua execução, que são as informações do certificado que vamos gerar. 

Para gerar o certificado, execute a seguinte linha de comando: 

keytool -genkey -alias guj -keyalg RSA -keypass guj123 -storepass guj123 -keystore C:/guj.jks -dname "cn=GUJ, ou=Artigo, o=GUJ, l=Sao Paulo, S=SP, c=BR" -validity 365


O comando acima, deve gerar o arquivo do certificado digital no caminho "C:\\guj.jks". 

Os argumentos passados para o keytool são: 

-genkey : para indicar que vamos gerar a chave. 
-alias : é o nome das chaves que serão armazenadas no keystore. No nosso caso é "guj". 
-keyalg : indica qual o algorítmo que vamos usar. No nosso caso RSA. O padrão é DSA. 
-keypass : indica a senha de proteção da chave no keystore. 
-storepass : é a senha de proteção do keystore. 
-keystore : indica onde as chaves serão armazenadas. Se nada for informado, por padrão (no Windows) é armazenada em user.home/.keystore. 
-dname : nome da entidade que vai gerar o par de chaves. Exemplo: cn = Nome Comun, ou = Unidade Organizacional (departamento ou divisão), o = Nome da Organização, l = localidade (cidade), s = Estado, c = País. 

Pronto! Agora já sabemos como criar nosso certificado digital, que possui um par de chaves privada e pública. 

Caso você necessite extrair a chave pública do seu certificado, para passar a alguém, você precisa do certificado para exportar a chave. Você deve executar o seguinte comando: 

keytool -export -alias guj -keystore C:/guj.jks -file C:/guj.x509


-export : informa que você vai exportar a chave. 
-alias : é o nome dados para a chave. 
-keystore : onde o certificado foi armazenado. 
-file : novo arquivo gerado, que é a chave pública exportada no formato X509. 

Existe uma ferramente visual para se criar e extrair os certificados digitais. Ela se chama KeyTool Explorer e pode ser encontrada em: http://www.lazgosoftware.com/kse/index.html 





Agora que temos o certificado, precisamos de uma maneira de extrair essas chaves, dentro do Java, para podermos utilizá-las para encriptação e decriptação dos dados. 

O método que simplifica a extração das chaves é o seguinte: 

01     public static PrivateKey getPrivateKeyFromFileFile cert, String alias, String password throws Exception {
02         KeyStore ks = KeyStore.getInstance "JKS" );
03         char[] pwd = password.toCharArray();
04         InputStream is = new FileInputStreamcert );
05         ks.loadis, pwd );
06         is.close();
07         Key key = ks.getKeyalias, pwd );
08         ifkey instanceof PrivateKey ) {
09             return (PrivateKeykey;
10         }
11         return null;
12     }
13 
14     /**
15      * Extrai a chave pública do arquivo.
16      */
17     public static PublicKey getPublicKeyFromFileFile cert, String alias, String password throws Exception {
18         KeyStore ks = KeyStore.getInstance "JKS" );
19         char[] pwd = password.toCharArray();
20         InputStream is = new FileInputStreamcert );
21         ks.loadis, pwd );
22         Key key = ks.getKeyalias, pwd );
23         Certificate c = ks.getCertificatealias );
24         PublicKey p = c.getPublicKey();
25         return p;
26     }


Na chamada dos métodos informamos: 

File cert : Arquivo do certificado digital. 
String alias : alias das chaves no keystore. 
String password : senha das chaves. 

Para pegar uma instância do KeyStore, informamos JKS, que é o formato default na geração das chaves. Este é um tipo proprietário da implementação de keystore da Sun. 





Agora que já possuímos as chaves pública e privada, vamos ver como encriptar e decriptar (verificar) os dados. 

01     /**
02      * Retorna a assinatura para o buffer de bytes, usando a chave privada.
03      @param key PrivateKey
04      @param buffer Array de bytes a ser assinado.
05      */
06     public static byte[] createSignaturePrivateKey key, byte[] buffer throws Exception {
07         Signature sig = Signature.getInstancesignatureAlgorithm );
08         sig.initSign(key);
09         sig.update(buffer, 0, buffer.length);
10         return sig.sign();
11     }
12 
13     /**
14      * Verifica a assinatura para o buffer de bytes, usando a chave pública.
15      @param key PublicKey
16      @param buffer Array de bytes a ser verficado.
17      @param sgined Array de bytes assinado (encriptado) a ser verficado.
18      */
19     public static boolean verifySignaturePublicKey key, byte[] buffer, byte[] signed throws Exception {
20         Signature sig = Signature.getInstancesignatureAlgorithm );
21         sig.initVerify(key);
22         sig.update(buffer, 0, buffer.length);
23         return sig.verifysigned );
24     }


Os dois métodos são bem simples e nos fornecem maneiras de encriptar os dados, na forma de array de bytes e também fornece uma maneira de verificar o dado assinado. 




Para finalizar, vamos ver realmente como utilizar toda esta parafernalha. 

01     public static void main(String[] args) {
02         String txt = "String a ser encriptada";
03 
04         try {
05             File cert = new File("C:/guj.jks");
06             String alias = "guj";
07             String pwd = "guj123";
08 
09             PrivateKey privateKey = getPrivateKeyFromFilecert, alias, pwd );
10             PublicKey publicKey = getPublicKeyFromFilecert, alias, pwd );
11 
12             byte[] txtAssinado = createSignatureprivateKey, txt.getBytes() );
13 
14             System.out.printlntxt2HexatxtAssinado ) );
15 
16             ifverifySignaturepublicKey, txt.getBytes(), txtAssinado ) ) {
17                 System.out.println("Assinatura OK!");
18             else {
19                 System.out.println("Assinatura NOT OK!");
20             }
21 
22         catchException e ) {
23             e.printStackTrace();
24         }
25     }


Criamos um File que representa para nosso arquivo de certificado em disco e em seguida extraimos as chaves privada e pública. 

Com o método createSignature() nós assinamos a String txt, que é o dado que desejamos encriptar (assinar). Em seguida, imprimimos na tela a representação hexadecimal da assinatura gerada. 

E, por fim, verificamos a assinatura com o método verifySignature(). O método verifica se o dado em txt é correspondente ao dado assinado (encriptado). 

O método para converter para a representação hexadecimal é o seguinte: 

01     /**
02      * Converte um array de byte em uma representação, em String, de seus hexadecimais.
03      */
04     public static String txt2Hexa(byte[] bytes) {
05         ifbytes == null return null;
06         String hexDigits = "0123456789abcdef";
07         StringBuffer sbuffer = new StringBuffer();
08         for (int i = 0; i < bytes.length; i++) {
09             int j = ((intbytes[i]) 0xFF;
10             sbuffer.append(hexDigits.charAt(j / 16));
11             sbuffer.append(hexDigits.charAt(j % 16));
12         }
13         return sbuffer.toString();
14     }


Conclusão 

A princípio a assinatura de dados utilizando certificado digital não parece muito simples ou trivial. Mas espero que, com este material, a vida de muitos, que precisam trabalhar com isso, possa se tornar mais fácil. 

Faça o download do arquivo Java completo deste tutorial. 

Abraços e até a próxima! 

Por Daniel Destro 
Fonte : http://www.guj.com.br/java.tutorial.artigo.141.1.guj