estudo de tecnicas de progra - siaibib01.univali.brsiaibib01.univali.br/pdf/guilherme denardi de...

116
UNIVERSIDADE DO VALE DO ITAJAÍ CENTRO DE EDUCAÇÃO SUPERIOR DE CIÊNCIAS TECNOLÓGICAS, DA TERRA E DO MAR CURSO DE CIÊNCIA DA COMPUTAÇÃO ESTUDO DE TÉCNICAS DE PROGRAMAÇÃO SEGURA EM JAVA NA PERSPECTIVA COMPUTACIONAL Área de Segurança em Redes de Computadores Guilherme Denardi de Britto Itajaí (SC), Junho de 2004

Upload: trananh

Post on 28-May-2018

215 views

Category:

Documents


0 download

TRANSCRIPT

UNIVERSIDADE DO VALE DO ITAJAÍ CENTRO DE EDUCAÇÃO SUPERIOR DE CIÊNCIAS TECNOLÓGICAS, DA TERRA E DO MAR CURSO DE CIÊNCIA DA COMPUTAÇÃO

ESTUDO DE TÉCNICAS DE PROGRAMAÇÃO SEGURA EM JAVA NA PERSPECTIVA COMPUTACIONAL

Área de Segurança em Redes de Computadores

Guilherme Denardi de Britto

Itajaí (SC), Junho de 2004

UNIVERSIDADE DO VALE DO ITAJAÍ CENTRO DE EDUCAÇÃO SUPERIOR DE CIÊNCIAS TECNOLÓGICAS, DA TERRA E DO MAR CURSO DE CIÊNCIA DA COMPUTAÇÃO RELATÓRIO DO TRABALHO DE CONCLUSÃO DE CURSO I I

ESTUDO DE TÉCNICAS DE PROGRAMAÇÃO SEGURA EM JAVA NA PERSPECTIVA COMPUTACIONAL

Área de Segurança em Redes de Computadores

Guilherme Denardi de Britto

Relatório apresentado à Banca Examinadora do Trabalho de Conclusão do Curso de Ciência da Computação para análise e aprovação

Itajaí (SC), Junho de 2004

i

EQUIPE TÉCNICA

Acadêmico Guilherme Denardi de Britto

Professora Or ientadora Carla Merkle Westphall, Dra.

Coordenadores dos Trabalhos de Conclusão de Curso Anita Maria da Rocha Fernandes, Dra.

César Albenes Zeferino, Dr.

Coordenador do Curso Luis Carlos Martins, Esp.

ii

DEDICATÓRIA

Dedico este trabalho ao meu Pai João Carlos de Britto, a minha mãe Salete Claire de Britto e a minha filha Adrielle Brocardo dos Santos de Britto.

iii

AGRADECIMENTOS

A minha mãe Salete Claire de Britto, que sempre me incentivou nos estudos e me deu força nos momentos mais difíceis.

Ao meu irmão Cristhian que sempre acreditou na minha capacidade e sempre esteve ao meu lado

A minha irmã Camila pela companhia nas madrugadas, nas conversas para descontrair

A Ariane que cuidou muito bem da nossa filha durante este trabalho, me tranqüil izando e me incentivando muito

A minha filha Adrielle, pois era nela que eu pensava nos momentos mais difíceis do trabalho e onde eu achava força para seguir adiante

A Carla Merkle Westphall, que não apenas me orientou, mas também me guiou para que eu conseguisse chegar ao termino deste trabalho

Aos meus amigos Julio César Fiamoncini, Fernando Rossi e Rafael Martins com os quais estive junto em toda essa jornada estudando e nos divertindo

E a todos os Professores por terem compartilhado seus conhecimentos e me ajudado por esta longa

caminhada

iv

SUMÁRIO

EQUIPE TÉCNICA....................................................................................i

DEDICATÓRIA.........................................................................................ii

AGRADECIMENTOS..............................................................................iii

LISTA DE ABREVIAÇÕES E SIGLAS..............................................viii

LISTA DE FIGURAS...............................................................................ix

LISTA DE TABELAS...............................................................................xi

RESUMO.................................................................................................xiii

ABSTRACT.............................................................................................xiv

I – INTRODUÇÃO...................................................................................01

1. APRESENTAÇÃO ...............................................................................01

2. JUSTIFICATIVA.................................................................................02

3. IMPORTÂNCIA DO TRABALHO....................................................02

4. OBJETIVO DO TRABALHO............................................................03

4.1 OBJETIVOS GERAIS........................................................................................03

4.2 OBJETIVOS ESPECÍFICOS.............................................................................03

5. METODOLOGIA................................................................................04

II – REVISÃO BIBLIOGRÁFICA.........................................................06

1. SEGURANÇA COMPUTACIONAL .................................................06

1.1 POLÍTICAS DE SEGURANÇA ........................................................................07

1.1.1 Segurança, Pr ivacidade e Confidencialidade.................................................07

1.1.2 Tipos de Políticas..............................................................................................07

1.2 PERÍMETROS DE SEGURANÇA ...................................................................08

1.3 VULNERABILIDADE, AMEAÇAS, RISCOS E ATAQUES.........................09

1.4 PROPRIEDADES DE SEGURANÇA ...............................................................10

1.5 PRINCÍPIOS DE SEGURANÇA .......................................................................11

v

1.6 MECANISMOS DE SEGURANÇA ..................................................................12

1.6.1 Controle de Acesso............................................................................................12

1.6.1.1 Modelos de Controle de Acesso......................................................................13

1.6.1.2 Domínios de Proteção......................................................................................13

1.6.2 Cr iptografia.......................................................................................................14

1.6.3 Autenticação......................................................................................................14

2. MODELO DE SEGURANÇA DO JAVA ..........................................16

2.1 INTRODUÇÃO A L INGUAGEM .....................................................................16

2.2 MODELO CAIXA DE AREIA (SANDBOX)...................................................17

2.2.1 O Verificador de Bytecodes.............................................................................18

2.2.2 O Carregador de Classes.................................................................................19

2.2.3 O Gerenciador de Segurança...........................................................................21

2.3 MODELO COM ASSINATURA DIGITAL .....................................................22

2.4 MODELO COM DOMÍNIO DE PROTEÇÃO................................................23

2.5 EVOLUÇÃO DO MODELO DE SEGURANÇA .............................................25

3. API CRIPTOGRÁFICA DO JAVA (JCE)........................................26

4. SERVIÇO DE AUTORIZAÇÃO E AUTENTICAÇÃO DO JAVA

(JAAS).......................................................................................................27

III – DESENVOLVIMENTO..................................................................30

1. CONTROLE DE ACESSO..................................................................30

1.1 PERMISSÕES.....................................................................................................30

1.1.1 Java.secur ity.Permission.........................…………………………………...31

1.1.2 Java.io.FilePermission....................................................................................31

1.1.3 Java.net.SocketPermission……………………………………………….…33

1.1.4 Java.secur ity.BasicPermission……………………………………………...35

1.1.5 Java.Secur ity.AllPermission………………………………………………...36

1.2 A ESTRATÉGIA PADRÃO DO JAVA ............................................................36

1.3 DOMÍNIO DE PROTEÇÃO..............................................................................38

vi

1.4 A CLASSE AccessController.............................................................................40

1.5 TÉCNICAS DE IMPLEMENTAÇÃO E TESTES..........................................41

1.5.1 Aplicação Propr iedadesLocal..........................................................................41

1.5.2 SocketServidor e SocketCliente.......................................................................46

1.5.3 Applet AppletTeste...........................................................................................50

2. CRIPTOGRAFIA.................................................................................54

2.1 JAVA CRY PTOGRAPHY ARCHITECTURE (JCA)....................................54

2.1.1 Classe Provider.................................................................................................56

2.1.2 Classe Secur ity..........................................……..................... ...........................57

2.1.3 Classe MessageDigest.......................................................................................58

2.1.4 Classe Signature................................................................................................59

2.1.5 Classe Algor ithmParameter....................................……................................61

2.1.5.1 Classes e Interfaces para especificação dos Parâmetros do algoritmo............61

2.1.5.2 Classe AlgorithmParameter.............................................................................62

2.1.6 Classe KeyFactory............................................................................................63

2.1.7 Classe CertificateFactory..................……......................... ..............................64

2.1.8 Classe KeyPairGenerator ................................................................................65

2.1.8.1 Inicialização com Algoritmo Independente.....................................................66

2.1.8.2 Inicialização com Algoritmo Específico.........................................................66

2.1.9 Classe Keystore.................................................................................................67

2.1.9.1 Entrada de Chave.............................................................................................67

2.1.9.2 Entrada de Certificado Confiável....................................................................68

2.1.10 Classe SecureRandom..........................................................……..................69

2.2 JAVA CRY PTOGRAPHY EXTENSION (JCE)..............................................70

2.2.1 Classe Cipher....................................................................................................71

2.2.2 Classe MAC.......................................................................................................74

2.2.3 Classe KeyGenerator ..........................……......................................................75

2.2.4 Classe KeyAgreement.......................................................................................76

2.2.5 Classe SealedObject....................……..............................................................77

vii

2.3 TÉCNICAS DE IMPLEMENTAÇÃO E TESTES..........................................78

2.3.1 MessageDigest com MD5.................................................................................78

2.3.2 DESTeste...........................................................................................................79

3. FERRAMENTAS RELACIOANDAS................................................81

3.1 KEYTOOL ...........................................................................................................83

3.2 JARSIGNER.................................................……...............................................85

3.3 POLICYTOOL ....................................................................................................86

IV – CONCLUSÕES E RECOMENDAÇÕES......................................96

BIBLIOGRAFIA......................................................................................98

viii

LISTA DE ABREVIAÇÕES E SIGLAS

AES Advanced Encryption Standard

API Applications Programming Interfaces

CA Certification Authority

CPU Central Processing Unit

CRL Certificate Revocation List

CSP Cryptographic Service Provider

CSR Certificate Signing Request

DAC Descretionary Access Control

DNS Domain Name System

DoD Department Of Defense

DoS Denial Of Service

DSA Digital Signature Algorithm

ECB Eletronic CodeBook

GSS-API Generic Security Services API

HTML HyperText Markup Language

HTTP HyperText Transfer Protocol

IP Internet Protocol

JAAS Java Authentication and Authorization Service

JAR Java ARchive

JCA Java Cryptography Architecture

JCE Java Cryptography Extension

JDK Java Development Kit

JRE Java Runtime Environment

JSDK Java Standard Developer Kit

LAN Local Area Network

MAC Mandatory Access Control

RBAC Role-Based Access Control

RMI Remote Method Invocation

RSA Rivest, Shamir e Adleman

URL Uniform Resource Locator

WWW World Wide Web

ix

LISTA DE FIGURAS

Figura 01 Modelo Caixa de Areia, JDK 1.0…………………………............. ...............17

Figura 02 Modelo com Assinatura Digital, JDK 1.1.......................................................22

Figura 03 Modelo com Domínio de Proteção, JDK 1.2..................................................24

Figura 04 Arquivo de política padrão “ java.policy” .......................................................37

Figura 05 Arquivo de segurança do Java “java.security” ................................................38

Figura 06 Exemplo de um Domínio de Proteção............................................................39

Figura 07 Exemplo de Controlador de acesso para uma permissão específica...............40

Figura 08 Código Fonte de uma aplicação que lê várias propriedades locais.................42

Figura 09 Código Fonte compilado e executado sem o uso do Controlador de Acesso.43

Figura 10 Execução da Aplicação PropriedadesLocal de modo seguro..........................43

Figura 11 Alterações na Aplicação PropriedadesLocal...................................................44

Figura 12 Arquivo de política com as novas entradas de permissão...............................45

Figura 13 Execução da Aplicação PropriedadesLocal com as alterações ......................45

Figura 14 Aplicação SocketServidor...............................................................................46

Figura 15 Aplicação SocketCliente.................................................................................47

Figura 16 Execução da Aplicação SocketServidor de modo seguro...............................47

Figura 17 Execução da Aplicação SocketCliente de modo seguro.................................47

Figura 18 Alterações na Aplicação SocketServidor........................................................48

Figura 19 Alterações na Aplicação SocketCliente..........................................................49

Figura 20 Alterações no Arquivo “ java.policy” ..............................................................49

Figura 21 Execução da Aplicação SocketServidor com as alterações............................50

Figura 22 Execução da Aplicação SocketCliente com as Alterações.............................51

Figura 23 Código fonte do Applet AppletTeste..............................................................51

Figura 24 Execução do applet AppletTeste.....................................................................51

Figura 25 Execução do AppletTeste mostrado pelo Appletviewer.................................51

Figura 26 Alterações no AppletTeste..............................................................................52

Figura 27 Alterações no Arquivo “ java.policy” ..............................................................52

Figura 28 Execução do AppletTeste com as Alterações.................................................53

Figura 29 Execução do AppletTeste alterado mostrado pelo Appletviewer...................53

Figura 30 Pasta TesteApplet............................................................................................53

Figura 31 Arquivo saída.txt.............................................................................................54

x

Figura 32 Arquivo java.security mostrando a lista de provedores..................................56

Figura 33 Provedor JCE pré-instalado no arquivo java.security.....................................70

Figura 34 Aplicação MDTeste........................................................................................78

Figura 35 Hash da Message Digest MDTeste.................................................................79

Figura 36 Aplicação DESTeste.......................................................................................80

Figura 37 Resultado do 1º teste com criptografia usando DES.......................................80

Figura 38 Resultado do 2º teste com criptografia usando DES.......................................81

Figura 39 Applet writeFile...............................................................................................82

Figura 40 Criação de um arquivo JAR............................................................................82

Figura 41 Criando as chaves e adicionando um keystore................................................84

Figura 42 Pedido de uma assinatura de certificado CSR................................................84

Figura 43 Arquivo JAR sendo assinado..........................................................................85

Figura 44 Exportando um certificado..............................................................................85

Figura 45 Importação de certificado confiável................................................................86

Figura 46 Iniciando o policytool......................................................................................86

Figura 47 Tela inicial do policytool.................................................................................87

Figura 48 Especifica o local do keystore.........................................................................87

Figura 49 Local do Keystore já adicionado.....................................................................88

Figura 50 Adiciona uma entrada no arquivo de política..................................................89

Figura 51 Adiciona permissão..........................................................................................89

Figura 52 Permissão adicionada.......................................................................................90

Figura 53 Arquivo de política com uma entrada adicionada.............................................91

Figura 54 Criando novo arquivo de política......................................................................91

Figura 55 Adicionando uma entrada no arquivo de Segurança do Java............................92

Figura 56 Arquivo HTML para executar o applet sWriteFile.jar.....................................92

Figura 57 Aviso de segurança...........................................................................................93

Figura 58 Detalhes do certificado......................................................................................93

Figura 59 Resultado da execução do applet writeFile.java..............................................94

Figura 60 Diagrama de Classes.........................................................................................95

xi

LISTA DE TABELAS

Tabela 01 Sintaxe para convenção dos nomes dos arquivos..............................................32

Tabela 02 Exemplo de construção de um objeto de permissão..........................................33

Tabela 03 Especificação do nome dos hosts......................................................................33

Tabela 04 Especificação da porta.......................................................................................34

Tabela 05 Exemplos de construção de permissões de soquete...........................................34

Tabela 06 Construtores da classe BasicPermission............................................................36

Tabela 07 Construtor da Classe AllPermission..................................................................36

Tabela 08 Construtor de um Domínio de Proteção............................................................39

Tabela 09 Métodos da Classe Provider..............................................................................57

Tabela 10 Métodos para adicionar um provedor à lista de provedores..............................58

Tabela 11 Principais métodos da Classe MessageDigest...................................................59

Tabela 12 Métodos para gerar um objeto de assinatura.....................................................60

Tabela 13 Métodos para inicializar um Objeto Signature..................................................60

Tabela 14 Métodos para adicionar dados ao objeto...........................................................61

Tabela 15 Métodos para Gerar e Verificar Assinaturas.....................................................61

Tabela 16 Métodos da Classe AlgorithmParameter...........................................................62

Tabela 17 Método para criação do Objeto KeyFactory......................................................63

Tabela 18 Conversão entre um objeto chave e uma especificação de chave.....................64

Tabela 19 Cria e Gera objetos Certificate e CRL...............................................................64

Tabela 20 Gera pares de chaves pública e privada.............................................................65

Tabela 21 Inicializa o KeyPairGenerator para um algoritmo independente......................66

Tabela 22 Inicializa o KeyPairGenerator para um algoritmo Específico..........................67

Tabela 23 Método para construir um par de chaves...........................................................67

Tabela 24 Principais métodos do KeyStore........................................................................68

Tabela 25 Principais métodos da classe SecureRandom....................................................69

Tabela 26 Métodos para criar objetos Cipher....................................................................71

Tabela 27 Métodos para incializar um objeto Cipher........................................................72

Tabela 28 Métodos para cifrar e decifrar dados em uma única operação..........................73

Tabela 29 Métodos para cifrar e decifrar dados em múltiplas operações..........................73

Tabela 30 Método para proteger uma chave e obtê-la novamente.....................................73

Tabela 31 Principais métodos da Classe MAC..................................................................74

Tabela 32 Principais Métodos da Classe KeyGenerator....................................................75

xii

Tabela 33 Principais métodos da Classe KeyAgreement...................................................76

Tabela 34 Código para criar um SealedObject...................................................................77

Tabela 35 Código para obter o Objeto original novamente...............................................77

Tabela 36 Principais comandos da ferramenta Keytool.....................................................83

xiii

RESUMO

A segurança de sistemas informáticos torna-se cada vez mais importante e essencial para o bom

funcionamento de uma organização. A programação segura de sistemas é um assunto de especial

interesse de pesquisa por ser um dos fundamentos para a segurança de ambientes como a Internet.

As técnicas de programação segura são cada vez mais estudadas pela preocupação que se tem

atualmente com o requisito segurança de sistemas computacionais. Esse Trabalho se propôs ao

estudo de algumas técnicas de programação segura fornecidas pela linguagem Java, como o

Controle de Acesso e Criptografia. Optou-se por estas duas técnicas devido à precariedade de

material e por estarem diretamente relacionadas à evolução dos modelos de segurança do Java.

Além disso, com essas técnicas é possível obter um ambiente seguro para executar códigos locais e

remotos, assim como, assinar códigos e trocar mensagens e dados de maneira segura. Foram

estudadas as principais classes destas APIs e criados exemplos do uso de algumas classes através de

programas teste. Com isto, este trabalho serve também como um guia para ser usado passo a passo

tanto por desenvolvedores, como também, administradores de sistemas.

xiv

ABSTRACT

The security of computing systems becomes more and more important and essential for the good

functioning of an organization. The safe programming of systems is a subject of especial interest of

research for being one of the basis for the environment security as the internet. The development of

techniques of safe programming is more and more studied for the concern that it has had with the

security requisite of computational systems currently. This paper if it proposes to the study of some

techniques of security programming supplied by the language Java, as the Access Control and

Cryptography. It opted for these ones two techniques due to the material precariousness and for are

directly related to the safety models evolution of Java. Besides, with these techniques is possible to

obtain a safe environment to execute local and remote codes, as well as, sign codes and change

messages and data of trusted manner. Were going studied the main classes this APIs and create

examples of some classes through programs test. With this, this paper serves also as a guide to be

used step-by-step so much for developers, as well as, systems managers.

I - INTRODUÇÃO

1. APRESENTAÇÃO

A segurança de sistemas informáticos distribuídos, construídos sobre redes como a

Internet, torna-se cada vez mais importante e essencial para o bom funcionamento de uma

organização.

A programação segura de sistemas é um assunto de especial interesse de pesquisa por ser

um dos fundamentos para a segurança de ambientes como a Internet. O desenvolvimento de

técnicas de programação segura é cada vez mais estudado pela preocupação que se tem atualmente

com o requisito segurança, tanto nos setores públicos quanto privados.

Atualmente, existem várias ferramentas de tecnologia que podem ser usadas em

programas, desenvolvidos nas linguagens C e Java, que fornecem meios de se construir sistemas

mais seguros (McGRAW, 1997).

O conceito de Segurança em um sistema informático é identificado como a sua

capacidade de assegurar a prevenção ao acesso e a manipulação ilegítima da informação, ou, ainda,

de evitar a interferência indevida na sua operação normal (ISO/IEC 15408-1, 1999). Esta

capacidade está fundamentada sobre quatro propriedades que devem ser mantidas: a

confidencialidade, a integridade, a disponibilidade e a autenticidade.

Para que um programa seguro possa ser construído, é necessário que exista, além do

conhecimento de possíveis tecnologias e técnicas de construção de softwares seguros, o uso dessas

técnicas desde o início do processo de desenvolvimento (BROSE, 2002).

O grupo da Universidade de Princeton1 é pioneiro no estudo dos aspectos de segurança da

linguagem de programação Java (BALFANZ, 2000). Este grupo, atualmente, vem desenvolvendo

estudos sobre programação segura no ambiente da Internet. O trabalho de BALFANZ (2000)

1 http://www.cs.princeton.edu/sip/Research.html

2

descreve uma arquitetura de segurança para aplicações Java com o objetivo de possibili tar a um

cliente se autenticar e ser autorizado quando acessa um servidor distribuído.

Neste sentido este trabalho tem como foco principal o desenvolvimento de técnicas de

programação segura a fim de que se possa construir softwares melhores e menos vulneráveis a

situações indesejáveis. Invasores não poderão aproveitar falhas da linguagem para invadir os

sistemas nos quais as aplicações são executadas.

2. JUSTIFICATIVA

O presente trabalho fez o estudo das ferramentas de programação para desenvolver

técnicas de programação segura. Foram desenvolvidos programas teste para análise dos resultados.

Com isso este projeto se encaixa nos parâmetros de pesquisa do curso de Ciência da Computação.

3. IMPORTÂNCIA DO TRABALHO

A programação segura de sistemas é um assunto de especial interesse de pesquisa por ser

um dos fundamentos para a segurança de ambientes como a Internet. O desenvolvimento de

técnicas de programação segura é cada vez mais estudado pela preocupação que se tem atualmente

com o requisito segurança, tanto nos setores públicos quanto privados.

Há necessidade do desenvolvimento de técnicas de programação segura, pois as falhas

nestes sistemas podem deixá-los vulneráveis a invasões.

3

4. OBJETIVOS DO TRABALHO

4.1. OBJETIVO GERAL

O objetivo geral deste trabalho foi o estudo dos aspectos de segurança da linguagem Java

na perspectiva de segurança computacional e validação das técnicas através de programas teste.

4.2. OBJETIVOS ESPECÍFICOS

Os objetivos que devem ser seguidos na execução deste trabalho de conclusão estão

listados na seqüência:

⇒ Análise de um ambiente e da linguagem de programação Java, no que diz respeito a

problemas de segurança existentes;

⇒ Estudo das ferramentas de tecnologias existentes que podem ser usadas para se ter um

programa seguro;

⇒ Proposta inicial de um conjunto de técnicas para o desenvolvimento de programas

seguros, construindo roteiros;

⇒ Estudo dos mecanismos de segurança: controle de acesso e criptografia;

⇒ Programas teste validando modelos utili zando os mecanismos estudados;

⇒ Estudo das ferramentas relacionadas ao tema.

4

5. METODOLOGIA

A metodologia para o desenvolvimento do projeto Desenvolvimento de Técnicas de

Programação Segura foi baseada na execução de atividades.

As seguintes atividades foram executadas e compõem o plano de trabalho deste projeto:

Atividade 1. Estudo de conceitos básicos de segurança.

Essa atividade objetivou o conhecimento dos conceitos de segurança. Ficaram conhecidos

os conceitos como: ataque, principal, intruso, política de segurança, controle de acesso,

autenticação e criptografia.

Atividade 2. Análise e estudo de tecnologias de segurança que foram usadas para o

desenvolvimento de programas.

Essa atividade visou o estudo de tecnologias de segurança existentes como JCE (API de

Criptografia do Java) (SUN, 2002), JAAS (Serviço de Autenticação e Autorização para o Java), API

do Modelo de Segurança do Java (SUN 1995, SUN 1998, SUN 1999) e outras tecnologias

pertinentes.

Atividade 3. Definição inicial do conjunto de técnicas para o desenvolvimento de

programas seguros.

Esta atividade visou analisar a literatura relacionada e identificou técnicas existentes para

possível definição de técnicas a serem propostas neste projeto.

Atividade 4. Estudos das Classes do Controlador de Acesso.

Nesta atividade foi feito um estudo detalhado do mecanismo de controle de acesso, que

possui uma bibliografia escassa, ao final desta etapa, foram feitos teste validando o mecanismo

estudado.

5

Atividade 5. Estudo dos aspectos criptográficos do Java.

Nesta atividade, foram estudados o JCA e o JCE, suas principais classes e métodos. Ao

final desta etapa também foram feitos testes validando o mecanismo de criptografia

Atividade 6. Estudo e Teste com ferramentas relacionadas.

Para finalizar, foi feito um estudo das ferramentas disponíveis para auxiliar o uso de

algumas técnicas de segurança e em seguida foram testadas as ferramentas validando os resultados.

II . REVISÃO BIBLIOGRÁFICA

1. SEGURANÇA COMPUTACIONAL

Há algum tempo atrás, quando surgiu um dos primeiros computadores que ocupavam

andares dos prédios, os operadores se depararam com um fato interessante, um inseto havia ficado

preso dentro da máquina atrapalhando seu funcionamento, surgindo assim o termo (bug) inseto, que

se tornou sinônimo de falha no sistema. Hoje em dia quando é descoberta uma falha no sistema diz-

se que um novo bug foi descober to, com a evolução da tecnologia, desenvolveram-se ferramentas

que auxiliam na exploração desses bugs, causando insegurança nos sistemas (ASSUNÇÃO, 2002).

Na tentativa de minimizar esses danos, foram desenvolvidas linguagens e técnicas de

programação que visam diminuir os bugs de um sistema. Pois é através desses bugs que crakers

usam para invadir sistemas e roubar informações confidenciais de uma grande empresa, por

exemplo. Dentro dessas técnicas está o uso de mecanismos de segurança como a criptografia,

monitores de referência e também políticas de segurança que variam de acordo com o administrador

do sistema.

Conforme ASSUNÇÃO (2002), existe uma diferença entre um craker e um hacker que é

confundido. Um hacker é o curioso por natureza, tem por objetivo aprender e desenvolver seus

conhecimentos para ajudar os que precisam. Um bom exemplo e que realmente aconteceu foi o caso

do cracker Kevin Mitnick que invadiu o computador do analista de sistemas Shimomura.

Destruindo dados e roubando informações valiosas. Shimomura que é um hacker e possui melhor

conhecimento que seu inimigo digital, montou um honeypot (uma armadilha que consiste em criar

uma falsa rede para pegar invasores) e pegou Mitnick. Infelizmente a imprensa confundiu os termos

e referenciou os dois como hackers.

Um craker não possui respeito algum, invade sistemas, podendo apenas deixar sua marca

ou destruí-los totalmente. Muitas vezes começam na adolescência para querer ganhar respeito e

ficarem conhecidos, e saem apagando tudo o que consegue, ou podem ser mestres em programação

que são contratados por empresas para espionagem industrial (Ibidem).

7

1.1. POLÍTICAS DE SEGURANÇA

Segundo LANDWEHR (2001), uma política de segurança é um conjunto definido de

regras que visa alcançar um objetivo particular, por exemplo, proteger processos computacionais ou

informações de uma organização.

As regras de uma política de segurança devem ser detalhadas suficientemente, para definir

como podem ser manipuladas as informações e recursos de uma organização. Devem definir

também o que é, e o que não é permitido em termos de segurança, durante a operação de um dado

sistema (LOUSANO et. al., 2000).

1.1.1. Segurança, Pr ivacidade e Confidencialidade

Segurança, privacidade e confidencialidade são termos que geralmente são confundidos ou

trocados. Segurança é o mais geral desses termos e pode, dependendo da política, aliar os conceitos

de privacidade e confidencialidade. Privacidade no contexto de políticas de segurança pode ser

definida como o poder de manter as informações em segredo (LANDWEHR, 2001). Já

confidencialidade, garante que usuários só podem ler informações para os quais estejam autorizados

(OBELHEIRO, 2001).

1.1.2. Tipos de Políticas

Os tipos de políticas de segurança são definidos dependendo da preocupação com o

sistema. Pode-se destacar a política:

• Mil itar: as pesquisas que levaram aos primeiros modelos de segurança

computacional, foram financiadas pelo DoD (Department Of Defense),

Departamento de Defesa dos Estados Unidos, na década de 70. Estes modelos

foram baseados em prática de segurança utilizada em áreas ligadas à segurança

nacional (OBELHEIRO, 2001). Os modelos mil itares são usados para guardar

informações importantes (sensíveis), dentre estas informações estão os planos e

8

estratégias confidenciais que tem um custo alto, tanto em valor monetário, como

no caso de uma guerra onde muitas vidas estão em perigo (LANDWEHR, 2001).

• Comercial: tem seu foco principal no fluxo e proteção dos recursos financeiros.

Isso é importante para prevenir e detectar fraudes comerciais, além de proteger

contra os concorrentes (Ibidem).

Conforme LANDWEHR (2001), existem outras áreas onde as políticas de segurança se

enquadram e são cruciais, um exemplo é a área da saúde onde os pacientes podem ter um grande

interesse em manter as informações de todos ou alguns aspectos de seus registros médicos

confidenciais.

1.2. PERÍMETROS DE SEGURANÇA

Na área de segurança computacional o primeiro passo é a identificação do que faz parte do

sistema e o que não faz. Esta atividade define os perímetros de segurança de um sistema e o

escopo do que precisa ser protegido e o que pode ser controlado (LANDWEHR, 2001).

Cada vez existem mais computadores conectados uns aos outros, alguns temporariamente

outros permanentemente, e trocando informações. Essas informações é que devem ser asseguradas.

Infelizmente, a configuração de máquinas clientes que são controladas pelos próprios usuários

podem ter um efeito significativo na segurança dos sistemas. Por exemplo, um usuário pode instalar

um modem no desktop conectado a rede interna da empresa, a fim de ganhar acesso como de uma

residência. Isso deve ser bem especificado para o usuário, que essa ação pode abrir um caminho

para um invasor entrar na rede interna da empresa sem passar pela cuidadosa configuração do

firewall que a organização usa para se proteger de ataques externos. (Ibidem)

Segundo LANDWEHR (2001), um dos propósitos que definem o perímetro de segurança

de um sistema é distinguir invasores de usuários legítimos. Um invasor é um individuo que

ultrapassa um perímetro de segurança de um sistema sem autorização. Este pode ganhar acesso ao

sistema roubando a identificação de um usuário legítimo, e o comportamento do invasor em um

sistema computacional pode ser difícil de ser diferenciado de um usuário comum, detectar tais

invasores é um problema difícil de resolver.

9

1.3. VULNERABILIDADE, AMEAÇAS, RISCOS E ATAQUES

Pode-se definir a vulnerabilidade como uma manifestação de falha de segurança, de

características não-maliciosas, que podem ser explorada com intenções maliciosas.

A ameaça é a intenção de causar danos a um sistema. Pessoas diferentes têm formas

diferentes de ameaçar (LANDWEHR, 2001). Algumas das principais ameaças em sistemas

descritas por LOUSANO (et. al., 2000) são: Destruição ou modificação de informações, roubo ou

revelação das informações. As ameaças podem ser acidentais ou intencionais:

• Acidentais: Não tem uma intenção premeditada associada a ela;

• Intencionais: São as que estão associadas à intenção premeditada.

Tanto para ameaças acidentais, como ameaças intencionais podem ser passivas ou ativas.

• Passivas: são ameaças que mesmo sendo realizadas não causam nenhum dano nas

informações contidas no sistema;

• Ativas: são ações que deformam as informações de um sistema, podendo também

alterar o seu estado ou operação.

O risco está diretamente ligado com a vulnerabilidade, pois um sistema vulnerável tem um

risco maior de ser invadido diante um ataque. Porém, para isso acontecer é necessário que haja uma

ameaça. Segundo LANDWEHR (2001), o risco cresce quando são encontradas falhas no software, e

a política deve evitar vulnerabilidade às ameaças.

Um ataque pode ser definido como uma ação maliciosa e intencional desencadeada com o

intuito de explorar uma vulnerabilidade potencial. Os principais ataques que podem ocorrer em um

ambiente de processamento e comunicação de dados são descritos por LOUSANO (et. al., 2000):

• Personificação: uma entidade faz-se passar por outra. Uma entidade que possui

poucos privilégios pode fingir ser outra, para obter privilégios;

• Replay: uma mensagem, ou parte dela é interceptada, e posteriormente transmitida

para produzir um efeito não autorizado;

• Modificação: o conteúdo de uma mensagem é alterado implicando em efeitos não

autorizados sem que o sistema consiga identificar a alteração;

10

• Negação de Serviço (DoS - Denial Of Service): ocorre quando uma entidade não

executa sua função apropriadamente ou atua de forma a impedir que outras

entidades executem suas funções;

• Ataques Internos: ocorrem quando usuários legítimos comportam-se de modo não

autorizado ou não esperado;

• Armadilhas: ocorre quando uma entidade do sistema é alterada para produzir

efeitos não autorizados em resposta a um comando (emitido pela entidade que está

atacando o sistema) ou a um evento, ou seqüência de eventos, premeditados;

• Cavalos de Tróia: uma entidade executa funções não autorizadas, em adição às que

está autorizado a executar.

1.4. PROPRIEDADES DE SEGURANÇA

Conforme LANDWEHR (2001), as definições convencionais de segurança computacional

exigiam que o sistema tivesse três propriedades:

• Confidencialidade: garante que os usuários do sistema só podem acessar

informações para os quais estejam autorizados; uma violação da confidencialidade

é chamada de revelação não-autorizada ou vazamento de informações

(OBELHEIRO, 2001). Obtém-se confidencialidade pelo controle de acesso

(senhas) e controle das operações individuais de cada usuário (log) (LOUSANO

et. al., 2000);

• Integridade: garante que o sistema não corrompa informações nem permita que

elas sejam modificadas de forma não-autorizada, independente do caráter

malicioso ou acidental das modificações (OBELHEIRO, 2001);

• Disponibilidade: previne a interrupção na operação de todo o sistema; uma quebra

do sistema não deve impedir o acesso aos dados (LOUSANO et. al., 2000). A

violação da disponibilidade é chamada de negação de serviço.

Recentemente foram incorporadas mais duas propriedades conforme LANDWEHR

(2001):

11

• Autenticação: assegura que cada pessoa é quem realmente diz ser. É um pré-

requisito para as três primeiras propriedades, já que sem autenticação não é

possível determinar se uma modificação foi autorizada;

• Não-repudiação: assegura que uma terceira parte pode convencer-se que um evento

ocorreu.

1.5. PRINCÍPIOS DE SEGURANÇA

Segundo LANDWEHR (2001), se você quiser manter um segredo não conte a ninguém e

nem anote. Alguns dos princípios de segurança como esse sustentam a segurança computacional no

mundo, onde pode-se afetar as funções de um projeto de segurança fornecidas por um sistema. A

interface usada pelo usuário para chamar essas funções, e o modo como essas funções são

implementadas dentro de um sistema computacional. Neste tópico serão mostrados tais princípios

que tem relevância na segurança computacional.

A responsabil idade em sistemas computacionais torna-se importante do ponto de vista do

bom comportamento dos usuários, e para isso são necessários algumas ressalvas: utilizar

mecanismos de autenticação para responsabilizar usuários em um sistema computacional; se o

sistema tiver funções controladas pela política de segurança, este deve ser autorizado, essa

autorização dele levar em conta a identificação e o papel do requerente; deve ser feita auditoria nas

seções críticas de modo que se possa traçar a rota atrás de uma pessoa (LANDWEHR, 2001).

Usando o princípio do menor privilégio pode-se garantir que uma pessoa só poderá

realizar uma determinada função, se tiver permissão concedida para realizá-la, isso significa que

uma pessoa só realizará ações que lhe forem permitidas, tornando assim o sistema mais seguro, pois

se o usuário tiver acesso livre pelo sistema poderá causar um dano acidentalmente, possibili tando

violações (Ibidem).

Torna-se interessante minimizar a variedade, o tamanho e a complexidade dos

componentes confiáveis. Com isso os componentes em um projeto de sistema, podem-se reduzir os

custos e os riscos, pois é mais fácil garantir que sua implementação será correta (Ibidem).

12

Como mecanismos de segurança são imperfeitos e podem falhar, é necessário criar

mecanismos diversos e complementares, para o caso de um ataque passar por um dos mecanismos

seja parado por outro, isso torna-se viável usando mecanismos de segurança em profundidade

(Ibidem).

1.6. MECANISMOS DE SEGURANÇA

Uma política de segurança e seus serviços podem ser implementados através de vários

mecanismos de segurança, entre eles, controle de acesso, autenticação e criptografia.

1.6.1. Controle de Acesso

Os mecanismos de controle de acesso são usados para garantir que o acesso a um recurso

seja limitado aos usuários devidamente autorizados

Existem inúmeros mecanismos que controlam o acesso de usuários a sistemas

computacionais, porém serão descritos dois mecanismos conhecidos: o monitor de referência e o

domínio de proteção.

O monitor de referência é o modelo conceitual do controle de acesso. É a entidade que

recebe todas as requisições de acesso dos sujeitos, essa requisição dependendo da política de

segurança pode ser autorizada ou negada.

Para que haja um melhor entendimento do assunto, é necessário definir alguns conceitos,

como Sujeitos e Objetos. Em OBELHEIRO (2001), Sujeito é entidade em um sistema

computacional que inicia requisições por recursos, por exemplo, o usuário ou o processo sendo

executado em nome de um usuário. O objeto é uma entidade que armazena informações do sistema,

por exemplo, arquivos, domínios terminais, entre outros.

Segundo OBELHEIRO (2001), controle de acesso é a mediação das requisições de

acessos a objetos iniciados pelos sujeitos.

13

1.6.1.1. Modelos de Controles de Acesso

Os modelos de controle de acesso encontrados na literatura são:

• DAC (Descretionary Access Control): Controle de Acesso Descricionário, é o

modelo no qual o proprietário da informação determina quem tem acesso a essas

informações, permitindo que dados sejam copiados de objeto para objeto. Caso ele

não tenha acesso aos dados originais, poderá acessar uma cópia dos dados

(OBELHEIRO, 2001);

• MAC (Mandatory Access Control): Controle de Acesso Obrigatório, utiliza a regra

de segurança centralizada, a qual dita as regras incontornáveis de acesso a

informações (OBELHEIRO, 2001);

• RBAC (Role-Based Access Control): No Controle de Acesso Baseado em Papéis,

os usuários tem acesso às informações de acordo com o seu papel ou função na

organização, e esses papeis são associados a usuários (Ibidem).

1.6.1.2. Domínios de Proteção

O domínio de proteção é um controle de acesso flexível, desde que possibilite que os

próprios criadores das políticas de proteção possam escrever estes programas. A idéia de domínio

de proteção é que este pode ser aplicado em ambientes ou contextos de proteção diferentes, ou seja,

diferentes contextos têm poderes diferentes, por exemplo, o modo de sistema usuário/supervisor.

Nesse sistema um programa sendo executado em modo supervisor tem o controle do sistema e da

máquina podendo até pará-la, já em modo usuário estes poderes se tornam restritos, o usuário só

pode acessar o que foi descrito na política (LAMPSON, 1971).

O conceito de domínio de proteção pode ser observado num sistema de mensagens, na

troca de mensagens entre os processos. Uma mensagem consiste em uma identificação do processo

que está chamando o outro, seguido por uma quantidade arbitrária de dados. A identificação é

fornecida pelo sistema, não podendo ser adulterada. Neste contexto tudo pertence a algum processo

e não pode ser acessado por qualquer outro processo que não seja o dono (Ibidem).

14

1.6.2. Cr iptografia

A criptografia transforma dados ou textos para uma forma que os mesmos não possam ser

lidos por uma pessoa que seja diferente de seu receptor (ASSUNÇÃO, 2002). De um modo geral, a

criptografia funciona da seguinte maneira: o emissor cifra os dados através de uma codificação ou

através de chave criptográfica, e envia-os ao destino. Quando os dados chegam ao seu destino, o

receptor faz o processo inverso, obtendo assim os dados originais.

A criptografia que utiliza chave criptográfica pode ser classificada quanto ao número de

chaves utilizadas, se utili za uma mesma chave para cifrar e decifrar é chamada simétrica, e se

utilizam duas chaves diferentes chama-se assimétrica.

Os algoritmos simétricos, também chamados de convencionais, util izam a mesma chave

entre emissor e receptor, muitas vezes através de um par de chaves pública/privada encontra-se uma

chave em comum. Já os algoritmos assimétricos utilizam chaves de criptografia pública e privada.

A chave pública pode ser divulgada, ao contrário da chave privada que deve ser mantida sob sigilo.

Sendo assim, quando uma pessoa quer enviar dados a outra pessoa, ela deve utilizar a mesma chave

pública que o receptor, com isso somente o receptor poderá decifrar os dados (LANDWEHR,

2001).

Porém se a pessoa que estiver enviando os dados cifrá-los com a sua própria chave

privada, isso se torna uma assinatura digital, e somente o receptor que possui a chave privada

poderá ler os dados (Ibidem). Um exemplo de criptografia assimétrica é o RSA que foi um

algoritmo desenvolvido em 1977 por R. Rivest, A. Shamir e L. Adleman.

1.6.3. Autenticação

A autenticação digital tem como objetivo comprovar que quem estiver querendo trocar

informações com o sistema é realmente quem ele diz ser, pode-se dizer que a autenticação é a forma

de se fazer o gerenciamento de identidade do usuário. Os mecanismos de autenticação mais

encontrados são: senhas, Smart Cards, Biometria e One-time password.

15

A Senha de acesso é o método mais util izado, pelas empresas para a autenticação de

usuários. Porém para garantir o seu uso adequado, deve-se definir uma política de senhas, em que

sejam criadas regras para a criação, troca e uso das mesmas. As regras definidas devem ser

divulgadas a todos os funcionários e colaboradores da organização.

Na autenticação com Smart Cards é utili zada a combinação de um cartão com uma senha.

Smart card é um tipo de cartão plástico semelhante a um cartão de crédito com um ou mais

microchips embutidos, capaz de armazenar e processar dados, e pode ser programado para

desempenhar inúmeras funções. É utilizado tanto para controle de acesso lógico como para controle

de acesso físico.

A biometria é a tecnologia utiliza a análise de características humanas, como impressões

digitais, retina, rosto e de padrões de voz e de assinatura. A vantagem sobre as outras tecnologias de

autenticação é que o usuário é identificado por características únicas, pessoais e intransferíveis,

dispensando o uso de senhas, cartões ou crachás. É utilizado tanto para controle de acesso físico

como para controle de acesso lógico.

A tecnologia one-time password consiste em fornecer uma senha de acesso diferente a

cada intervalo de tempo determinado, permitindo que o usuário se conecte naquele instante.

Essa tecnologia torna-se sem efeito a ação de sniffers, já que a cada conexão uma nova senha deve

ser informada, permitindo que seja utilizado um canal inseguro. Para a geração das senhas são

utilizados tokens no formato de cartões, chaveiros ou aparelhos semelhantes a calculadoras.

Segundo LOUSANO (2001), existem três situações para se fazer à autenticação

dependendo do ambiente onde será feita:

1. Os parceiros e os meios são todos confiáveis, podendo a identificação ser

confirmada através de uma senha;

2. Há confiança nas entidades e parceiros, porém os meios de comunicação não são

confiáveis, nessa situação usa-se a criptografia;

3. Os parceiros não confiam nem nas entidades e nem nos meios de comunicação,

sendo necessário o uso de assinatura digital.

16

2. MODELOS DE SEGURANÇA DO JAVA

Quando se pensa em segurança pode surgir a idéia de firewalls, mas a segurança em Java

está ligada à segurança lógica dos dados, ou, como uma aplicação remota pode ser executada em

uma máquina local e não ser uma ameaça ao sistema.

Neste capítulo serão mostrados os modelos de segurança da linguagem Java. Inicialmente

será feita uma introdução a linguagem Java, em seguida serão mostrados os recursos de segurança,

começando com o Java SDK (Standard Developer Kit) versão 1.0, passando as versões seguintes, o

modelo com assinatura digital e com domínio de proteção e para finalizar serão mostradas as

últimas evoluções do modelo de segurança do Java.

2.1. INTRODUÇÃO A LINGUAGEM JAVA

A linguagem Java teve grande repercussão quando foi anunciada devido ao interesse pela

WWW (World Wide Web), pois o Java podia criar páginas Web com conteúdo interativo e

dinâmico, para desenvolver aplicativos corporativos e de grande porte, para aprimorar a

funcionalidade dos servidores WWW, fornecer aplicativos para dispositivos destinados ao

consumidor final e para muitas outras funcionalidades, entre eles aplicativos mais seguros

(DEITEL & DEITEL, 2002).

Conforme DEITEL & DEITEL (2002), os programas em Java consistem em partes

chamadas classes, que são métodos que realizam tarefas e retornam as informações ao completá-las.

Pode-se programar pedaços de programas que serão necessários para formar um programa em Java.

Porém, existem as coleções de classes nas bibliotecas de classes Java, onde programadores podem

reutil izar. Essas bibliotecas são conhecidas como Java APIs (Applications Programming

Interfaces), e são as interfaces de programas aplicativos.

Existe outro tipo de programa em Java, chamada applet Java. Applets são programas Java

que podem ser embutidos em documentos HTML (HyperText Markup Language), ou seja , páginas

Web, quando um navegador carrega uma página Web que contém um applet, o applet é baixado

17

para o navegador e começa a ser executado. O navegador que executa um applet é chamado de

contêiner do applet. O Java J2SDK inclui um contêiner de applets conhecido por appletviewer, para

testar applets antes de ser embutida em uma página Web (Ibidem).

2.2. MODELO CAIXA DE AREIA (SANDBOX)

O modelo de segurança do Java, chamado caixa de areia, é o modelo usado quando se

deseja restringir os recursos computacionais de um sistema para uma aplicação, as restrições podem

variar de acordo com a aplicação, mas quer assegurar de que a aplicação estará restrita a sua caixa

de areia (OAKS, 1999).

O modelo caixa de areia do Java fornece um ambiente restrito dos recursos do sistema,

somente os recursos disponíveis na caixa de areia serão acessados por um código não confiável. A

Figura 1 mostra o primeiro modelo de caixa de areia disponível pelo Java no modelo de segurança

JDK 1.0 (SUN, 2003).

Figura 1 – Modelo caixa de areia JDK 1.0.

Fonte: (SUN, 2003)

OAKS (1999), faz uma analogia do modelo caixa de areia do Java que torna fácil o

entendimento, por exemplo, que se uma sobrinha visita a casa do seu tio, este considera muito

18

importante ter uma caixa de areia para a criança brincar, não apenas para protegê-la, mas também

para proteger os objetos de sua casa. A sua sobrinha não pode correr livremente pela casa, pois pode

estragar algum objeto da casa. Dessa mesma forma existem diversos aplicativos interessantes na

Internet, mas não se deve deixá-los rodando com acesso total ao sistema.

A caixa de areia do Java protege vários recursos de uma máquina e pode variar em

diversos níveis. Um computador pode ter acesso a vários recursos, entre eles estão, a memória local,

seu próprio sistema de arquivos, pode estar numa LAN (Local Area Network) e ter acesso a outros

computadores, para executar alguns aplicativos é necessário acessar um servidor web na rede local

ou na Internet, além dos dados que trafegam nessa rede e no próprio computador e a proteção desses

recursos formam a base do modelo caixa de areia do Java (Ibidem).

Por isso podemos imaginar diversas caixas de areia de diferente tamanhos para executar

um programa Java. Uma caixa de areia mínima possui os recursos básicos para executar um

programa, que tem acesso à CPU, à tela, ao teclado, ao mouse e à sua memória. Uma caixa de areia

padrão é aquela em que o programa tem acesso à CPU, à sua memória e ao servidor web a partir do

o applet qual foi carregado. Já uma caixa de areia aberta é aquela que o programa tem acesso total

aos recursos (Ibidem).

O modelo caixa de areia é composto por diversos elementos, possui um verificador de

bytecodes, carregador de classes, controlador de acesso, gerenciador de segurança, pacote de

segurança e um banco de dados de chaves.

2.2.1. O Verificador de Bytecodes

O verificador de bytecodes assegura que um bytecodes de um programa esteja de acordo

com as regras da linguagem Java. Um compilador mal intencionado poderia ser usado para criar ou

tirar proveito de uma falha de segurança ignorando as regras da linguagem (Ibidem).

O verificador de bytecodes fica dentro da máquina virtual do Java, nem os programadores

poderão acessá-lo e nem os usuários poderão interagir com ele. O verificador é responsável por

verificar várias características de um bytecodes. Ele verifica se o arquivo de classe tem o formato

19

correto, a definição completa, assegura que o arquivo de classe tem a extensão certa e etc. Prova

também que as Classes finais não foram instanciadas e métodos finais não foram redefinidos, não

existe conversão ilegal de tipos nem existe estouro de operandos de pilhas. Se o verificador de

bytecodes terminou sua tarefa é porque o programa atende às muitas restrições da linguagem Java

(Ibidem).

2.2.2. O Carregador de Classes

O carregador de classes do Java é importante no modelo de segurança porque existem

informações sobre as classes que somente ele conhece, por exemplo, se a classe veio da rede, ou

seja, a classe faz parte do aplicativo e, portanto não deve ser confiável, ou se veio do sistema de

arquivos local, sendo a classe parte do paginador e deve ser confiável. Outro fator importante é em

relação a regra de espaço de nome do Java. O nome completo de uma classe Java é qualificado pelo

nome do pacote ao qual a classe pertence, por exemplo, não existe nenhuma classe padrão

denominada String na API do Java, mas existe a classe java.lang.String. Porém não é obrigatório

que uma classe pertença a um pacote, sendo assim seu nome é o próprio nome da classe. Diz-se que

essas classes estão num pacote default. Entretanto, há um engano, existe um pacote default diferente

para cada carregador de classes na máquina virtual do Java. Por isso, se ao acessar uma página Web

e carregar um applet que utili za uma certa classe e depois acessar uma outra página que carrega um

applet que contém uma classe com o mesmo nome, o carregador de classe internamente terá que

fazer uma referência para cada uma das classes (Ibidem).

Conforme (OAKS, 1999), os passos para um carregador de classes carregar e definir uma

classe são os seguintes:

1. Para acessar uma classe, o carregador de classes deve localizar o objeto na classe

anteriormente definido e retornar o objeto;

2. O gerenciador de segurança é consultado a fim de saber se o programa tem acesso à

classe em questão. Se não tiver autorização, uma exceção de segurança é levantada.

Este passo é opcional;

3. Caso o passo anterior não seja executado, um carregador de classes interno é

consultado a fim de tentar carregar a classe do CLASSPATH. Se for bem sucedido, o

20

carregador de classes retorna. Isso assegura que classes do Java API não sejam

substituídas por classes carregadas pela rede ou de outras localizações;

4. O gerenciador de segurança é novamente consultado para verificar se o programa

pode criar o objeto em questão. Caso negativo, uma exceção é criada. Este passo

também é opcional;

5. O arquivo de classes é lido em um array de bytes, a forma na qual é lido o arquivo e

criado o array de bytes dependerá do carregador de classes util izado;

6. Os bytecodes são executados através do verificador de bytecodes;

7. Um objeto classe é construído através do bytecode. Neste o processo, os métodos

que definem a classe são criados;

8. Antes que o objeto possa ser util izado, todas as classes as quais ela referencia devem

ser localizadas pelo carregador de classes.

Existem vários tipos de carregadores de classes utilizados em programas Java, a seguir

será mostrado os primeiros carregadores de classes, como: Carregador de classes interno,

Carregador de classes de applet. Os carregadores de classes que surgiram posteriormente serão

mostrados conforme a versão (Ibidem).

O Carregador de classes interno é referenciado como carregador de classes default ou

carregador de classes básico, a maioria dos carregadores de classes internos são escritos em código

nativo para que possa ser acessados diretamente pela máquina virtual. Isso é fundamental para que a

máquina virtual consiga fazer a carga inicial das classes da API.

O Carregador de classes de applet tem poder para carregar classes via HTTP a partir de

uma rede. Não há um carregador de classe de aplicativos padrão na API do Java.

O Carregador de classes do arquivo JAR (Java ARchive) é um recurso importante em

muitos carregadores de classes. Possui a capacidade de carregar um único arquivo que contém

muitas classes acelerando a carga das classes.

21

2.2.3. O Gerenciador de Segurança

O gerenciador de segurança tem um papel fundamental no modelo de segurança do Java,

Segundo OAKS (1999), é o gerenciador de segurança que determina a maioria dos parâmetros da

caixa de areia, cabendo a ele decidir se uma operação será permitida ou não.

OAKS (1999), ainda resume muito bem o que vem a ser um gerenciador de segurança:

Gerenciador de segurança é responsável por

decidir sobre o acesso àquilo que normalmente

consideramos como os recursos de sistema operacional:

arquivos, soquetes de rede, impressoras, etc. O objetivo do

gerenciador de segurança é conceder acesso a cada classe

de acordo com o nível de confiança possuído pelo usuário.

Geralmente, isto significa conceder acesso total a classes

confiáveis (classes que tenham sido carregadas a partir do

sistema de arquivos) e limitar acesso quando é solicitado

por parte de uma classe não confiável (ou seja, uma classe

que foi carregada da rede). (OAKS, 1999)

O JDK 1.0 e 1.1, é muito raro encontrar aplicações com gerenciador de segurança, nessas

versões se tornava difícil escrever um gerenciador de segurança, pois somente no Java 1.2 teve

inicio o uso de um gerenciador de segurança default configurável pelo usuário e que pode servir

para a maioria das aplicações. O gerenciador de segurança é responsável por determinar a maioria

dos parâmetros da caixa de areia do Java, isto inclui, determinar as operações que devem ser

permitidas ou rejeitadas (Ibidem).

No Java 1.0 uma classe que é carregada a partir do CLASSPATH é considerada confiável,

e uma classe que é carregada de um carregador de classes não pode ser considerada confiável. O

Java 1.1 é bastante semelhante, porém se uma classe for carregada a partir de um arquivo JAR pode

ser assinado digitalmente e ganhar privilégios extras. Já no Java 1.2 uma classe que é carregada a

partir da API básica é considerada confiável e pode fazer qualquer operação que quiser, senão as

classes recebem privilégios de acordo com o local que foram carregadas (Ibidem).

22

2.3. MODELO COM ASSINATURA DIGITAL

Na versão seguinte o modelo de segurança JDK 1.1 foram feitas inúmeras melhorias, a

principal é que independente do código ser local ou remoto, este está sujeito a uma política de

segurança. Essa política define um conjunto de permissões disponíveis para um código de vários

assinantes ou localizações. Cada permissão especifica uma permissão de acesso a um determinado

recurso. E pode ser configurado por um usuário ou um administrador de sistemas. A Figura 2

mostra a segunda versão do modelo de segurança do Java (SUN, 2003).

Figura 02 – Modelo com Assinatura Digital, JDK 1.1

Fonte: (SUN, 2003)

Esse modelo usa o conceito de applets assinados. Uma applet que possui uma assinatura é

tratada como um código local e tem acesso a todos os recursos do sistema, e são inseridos em um

arquivo JAR assinado. Já aplicativos que não são assinados são colocados na caixa de areia e terão

acesso somente a recursos disponíveis nessa caixa de areia. A configuração da caixa de areia é feita

pelo administrador do sistema (SUN, 2003).

23

A assinatura digital é uma String de bits, que é calculado de alguns dados e de uma

entidade, sendo assim, num applet assinado, os dados são verificados se vieram da entidade e não

foram modificados em trânsito. (SUN, 2003)

No JDK 1.1 também foi implantada uma API para fornecer funcionalidades criptográficas

aos desenvolvedores, a chamada JCA (Java Cryptography Architecture), essa arquitetura

criptográfica inclui classes e interfaces para fornecer assinaturas digitais e message digest.

Também foi inclui um carregador de classes RMI, que apesar do nome Carregador de

classes RMI não precisa ser usado somente em uma aplicação RMI e não é um carregador de classe,

ou seja, não estende a classe ClassLoader. Sua função é semelhante ao carregador de classes de

applets, pois usa o protocolo HTTP para carregar o arquivo de classe desejada a partir da máquina

remota (OAKS, 1999).

O JDK 1.1 inclui um pacote de segurança. O pacote de segurança forma a base para

autenticação das classes Java assinadas, pois possui as classes que estão no pacote java.security.

Esse pacote está relacionado com a interface do provedor de segurança, o meio pelo quais diferentes

implementações de segurança podem ser acrescentadas ao pacote de segurança. Inclui-se também

um Banco de Dados de chaves que é um conjunto de chaves que serve para verificar a assinatura

digital de um arquivo assinado (Ibidem).

2.4. MODELO COM DOMÍNIO DE PROTEÇÃO

A versão mais recente do modelo de segurança do Java JDK 1.2 utiliza o conceito de

domínios, e pode-se entender melhor visualizando a Figura 3. Um domínio individual inclui um

conjunto de classes cujas instâncias são concedidas aos mesmos conjuntos de permissões. Um

domínio pode ser configurado da formas diversas, porém poderão opcionalmente estar sujeito a uma

política de segurança. Na Figura 3, o domínio à direita, terá as mesmas restrições que uma caixa de

areia. Em oposição, o domínio da esquerda, terá acesso total a todos os recursos do sistema. E o

domínio do meio, terá um menor restrição aos recursos que o domínio da direita e maior restrição

aos recursos que o domínio da esquerda (Ibidem).

24

Figura 3 – Modelo com Domínio de Proteção, JDK 1.2

Fonte: (SUN, 2003)

Um domínio de proteção pode ser definido como um conjunto de objetos que são

diretamente acessados por um principal. Um principal é uma entidade no sistema que possui

permissões e responsabilidades concedidas. Domínios de proteção possuem duas categorias

distintas: domínio de sistemas e domínio de aplicação. É importante que todos os acessos aos

recursos externos, como sistema de arquivos, serviços de redes, tela e teclado sejam acessíveis

somente pelos domínios do sistema (SUN, 1999).

Uma política de segurança do sistema, definida pelo usuário ou pelo administrador do

sistema, deve especificar quais domínios de proteção devem ser criados e quais permissões devem

ser fornecidas nesses domínios. O ambiente de execução Java mantém um mapeamento do código

(classes e instâncias) para seus domínios de proteção e permissões correspondentes. O conceito de

domínio implementa de certa forma o princípio do privilégio mínimo (Least privilege) (Ibidem).

No JDK 1.2 foram incluídos mais dois carregadores de classes: Carregador de classes

seguro possui um construtor protegido, sendo usado para fornecer a base para o desenvolvimento de

outros carregadores de classes; Carregador de classes URL também teve início na versão JDK 1.2,

possui um carregador de uso geral que carrega classes a partir de um conjunto de URLs (Uniform

Resource Locator) (OAKS, 1999).

25

Segundo OAKS (1999), foi criado mais um elemento no modelo de segurança do Java. O

controlador de acesso, que é um tanto quanto redundante, pois possui uma função semelhante ao

gerenciador de segurança, determinando quais os acessos a um recurso crítico de sistema são

permitidos ou negados. Com isso o controlador de acesso pode fazer tudo que um gerenciador de

segurança faz. O motivo por haver o gerenciador de segurança e o controlador de acesso é que nas

versões anteriores o gerenciador de segurança tinha que contar com uma lógica interna para

determinar se estratégia de segurança deveria entrar em vigor. Mudar a estratégia de segurança

exigia mudar o próprio gerenciador de segurança. Com o surgimento do controlador de acesso o

gerenciador passou a transferir essas decisões para o controlador de acesso.

O controlador de acesso é representado por uma única classe chamada AccessControl

possui um construtor privado, não podendo ser criado, existem vários métodos estáticos nesta classe

que determinam se uma operação deve ter êxito. O que determina se um acesso será permitido ou

negado é um conjunto de domínios de proteção que estarão na pilha quando o controlador de acesso

for chamado (Ibidem).

2.5. EVOLUÇÃO DO MODELO DE SEGURANÇA

O Java se encontra na versão 1.4, nessa versão foram incluídas diversas modificações,

dentre elas está à integração do JCE (Java Cryptography Extension), que é responsável pela

criptografia do Java, esse pacote será estudado separadamente a seguir, porém vale ressaltar que nas

versões anteriores, JDK 1.2 e 1.3 esse pacote era opcional.

Também foi integrado o serviço de autorização e autenticação do Java (JAAS), que

também será visto a parte. Outras duas novas características é o GSS-API (Generic Security

Services) que é uma API de serviços de seguranças gerais do Java. Essa API pode ser usado para

troca de mensagens segura. A outra característica é o Java Certification Path API que inclui novas

classes e métodos que permitem a construção e validação de certificados (SUN, 2003).

Foi incluída também uma ferramenta de política gráfica (Policy Tools) que é util izada para

disponibilizar especificações em um campo Principal que indica qual usuário tem as permissões do

controle de acesso garantidas. Também foram adicionadas três ferramentas de segurança para

26

ajudar os usuários a obter e gerenciar o Kerberos, é um esquema de autenticação. Além de uma

nova linha de certificados CA (Certification Authority) (SUN, 2003).

Já no Java 2 SDK 1.4.2 foi incluído o suporte para AES (Advanced Encryption Standard)

que é um padrão de criptografia avançado e foi adicionado ao provedor criptográfico SunJCE.

Também foi adicionado ao provedor da Sun suporte a algoritmos hash (Ibidem).

3. API CRIPTOGRÁFICA DO JAVA (JCE)

O componente do Java que trabalha com a criptografia real dos dados é o JCE (Java

Cryptography Extension), nas primeiras versões 1.2.x e 1.3.x o JCE não fazia parte do modelo de

segurança do Java.

Inicialmente o JCE 1.2 foi criado para estender a API de arquiteturas criptográficas do

Java o JCA, disponível na plataforma Java 2 e tinha incluído APIs e implementações de serviços

criptográficos que ficavam reprimidos aos regulamentos de controle de exportação dos Estados

Unidos, só estando disponível para o Estados Unidos e Canadá O JCE 1.2.2 através de mecanismos

de implementação que assegura que somente provedores qualificados poderão ser ligados no

Framework, tornou o essa versão exportável para outros países (SUN, 2002).

O JCE util iza um motor de criptografia para cifrar e decifrar os dados. Porém é importante

observar que os motores criptográficos da JCE não têm nenhuma ligação com a geração e

verificação de assinaturas digitais, estas possuem seus próprios algoritmos de codificação e

decodificação (Ibidem).

A JCE apresenta as chaves públicas e privadas e mais uma nova chave, a chave secreta.

Uma chave secreta é compartilhada entre duas partes em uma operação. A chave secreta é usada na

codificação simétrica, onde a mesma chave que cifrou os dados é usada para decifrá-los. Portanto

quem tiver a chave secreta e os dados cifrados, poderá ter acesso total aos dados. Isso traz um

problema interessante, pois a chave secreta não pode ser envia eletronicamente de forma não

confiável, pode ser distribuída por um disco flexível ou usando uma concordância de chaves, que é

feita trocando informações públicas para que se possa calcular uma chave secreta compartilhada.

27

Essa troca de informações é feita de modo que um espião não consiga calcular a mesma chave

secreta (OAKS, 1999).

O provedor de segurança da Sun JCE implementa um algoritmo de concordância

chamado, Concordância de Chaves de Diff ie-Hellman, que funciona da seguinte maneira: a

primeira parte (o transmissor) gera um par de chaves pública/privada e envia a chave pública e a

especificação do algoritmo do par de chaves a segunda parte (receptor). O receptor gera suas

próprias chaves usando a especificação algoritmo e envia a chave pública ao transmissor, que gera a

chave secreta utilizando as sua chave privada e a chave pública que o receptor lhe enviou. O

receptor faz a mesma coisa com sua chave privada e a chave pública do transmissor, de acordo com

as propriedades da concordância de chaves Diff ie-Hellman, será gerado a mesma chave secreta para

ambos. Eles convertem as chaves secretas em uma chave de codificação de dados padrão. O

transmissor codifica os dados e envia para o receptor que decodifica os dados (Ibidem).

4. SERVIÇO DE AUTORIZAÇÃO E AUTENTICAÇÃO DO JAVA

(JAAS)

O serviço de autorização e autenticação do Java (JAAS – Java Authentication and

Authorization Service) foi introduzido como um pacote opcional do Java 2 SDK, versão 1.3. E foi

integrado no Java 2 SDK versão 1.4.

O JAAS é uma API do Java que possui dois propósitos: autenticar usuários com segurança

determinando quem está executando um código Java, indiferente se o código está sendo executado

como uma aplicação, um applet, um bean, ou um servlet. E para autorizar usuários, assegurando

que eles terão os direitos de acesso (permissões) exigidas para fazer as ações desempenhadas (SUN,

2002).

Para tornar-se mais compreensível, será abordado o componente autenticação e em

seguida o componente autorização do Java.

28

A autenticação basicamente assegura que um usuário deverá especificar um nome e uma

senha particular. A autenticação do JAAS é executada num modo pluggable. Isso permite que

aplicações possam permanecer independentes de tecnologias de autenticação subjacentes. Novas

tecnologias ou atualizações podem ser ligadas sem exigir modificações da própria aplicação.

Os arquivos descritos serão: SampleAcn.java que contem uma classe de aplicação de

amostra (SampleAcn) e outra classe usada para manipular saídas de usuários.

SampleLoginModule.java a autenticação do usuário no SampleLoginModule consiste em uma

verificação simples de um nome e senha que um usuário tenha especificado. E a

SamplePrincipal.java é uma classe de amostra que implementa a interface Java.security.Principal

(Ibidem).

O método principal da classe SampleAcn é executar a autenticação e depois informar se foi

ou não sucedida. A autenticação de um usuário é simples, consiste em dois passos. Instanciar um

LoginContext e chamar o método login do LoginContext (Ibidem).

Em alguns casos um LoginModule deve se comunicar com o usuário para obter

informações de autenticação. O LoginModule usa um javax.security.auth.callback.CallbackHandler

para isso. Uma aplicação pode também escrever implementação CallbackHandler. A aplicação

passa o CallbackHandler como um argumento para a instancia LoginContext. O LoginContext

remete o CallbackHandler diretamente para o LoginModule subjacente (Ibidem).

O LoginModule passa o método manipulador CallbackHandler para um array destino

javax.security.auth.callback.Callback, por exemplo, um NameCallback para o nome do usuário e

um PasswordCallback para a senha, e o CallbackHandler executa a interação com o usuário e

coloca os valores apropriados nos Callbacks (Ibidem).

MyCallbackHandler manipula três tipos de Callbacks: NameCallback que iniciar um

usuário pelo nome de usuário, PasswordCallback para iniciar uma senha de usuário, e

TextOutputCallback para informar erros, advertências ou outras mensagens do SampleLoginModule

deseje enviar para o usuário (Ibidem).

29

O SampleLoginModule.java implementa a interface LoginModule que consiste

simplesmente em verificar se o nome e senha especificados pelo usuário estão corretos. Esta é uma

classe que pode ser configurada para qualquer ambiente. A classe SamplePrincipal.java é uma

amostra de implementação da interface Java.security.Principal (Ibidem).

O administrador do sistema determina a tecnologia de autenticação, ou LoginModule, para

ser usado em cada aplicação e configura-os em uma configuração de login. A origem das

informações de configurações, por exemplo, arquivos ou banco de dados, é a implementação

javax.security.auth.login.Configuration (Ibidem).

O componente responsável pela autorização do JAAS assegura que o visitante autenticado

tenha os direitos do controle de acesso (permissão) exigidos para fazer operações sensíveis de

segurança subseqüentes. Desde que o componente de autorização exija que a autenticação do

usuário seja antes completada (Ibidem).

A autorização do JAAS estende a arquitetura de segurança do Java, que usa uma política

de segurança para especificar quais direitos de acesso são garantidos para executar um código. Que

a arquitetura, introduzida na plataforma Java 2, é code-centric. Ou seja, as permissões são

garantidas baseada nas características do código: se é digitalmente assinado e se for por quem

(Ibidem).

A autorização do JAAS aumenta o controle de acesso code-centric com novos controles

de acesso centric-users. Permissões podem ser garantidas baseadas não somente no qual código está

sendo executado, mas também quem está executando-o.

Quando um usuário é autenticado pelo JAAS, um sujeito é criado para representar o

usuário autenticado. O sujeito é colocado em um conjunto de Principals, onde cada Principal

representa uma identificação do usuário. As permissões podem ser garantidas em uma política de

Principals específica. Depois do usuário ter sido autenticado, a aplicação pode associar o sujeito

com o contexto do controle de acesso atual. Para cada operação de segurança checada

subseqüentemente o Java runtime determina se a política garante a permissão solicitada, somente

para um Principal especificado. A operação só será permitida se o sujeito associado com o contexto

do controle de acesso tiver denominado Principal (Ibidem).

III . DESENVOLVIMENTO

1. CONTROLE DE ACESSO

O controle de acesso teve seu modelo inicial no Java versão 1.0, com o modelo caixa de

areia que restringia uma aplicação, que estava na caixa de areia, a acessar somente os recursos do

sistema para os quais tivesse permissão.

Nos modelos seguintes do Java, o modelo caixa de areia teve muitos avanços, como

possibili tar a um código remoto acessar recursos do sistema como um código local, aplicando

sempre uma política de segurança. Permitiu também criar domínios de proteção, ou seja, um

conjunto de classes, de um mesmo local, pertence a um mesmo domínio de proteção se tiverem os

mesmos privilégios.

Este capítulo trata dos seguintes assuntos:

¬ Permissões: as principais classes de permissão do pacote de segurança do Java;

¬ A estratégia padrão do Java: apresenta os arquivos de estratégias que são instalados

no Java 2 SDK, os arquivos java.policy e o java.security;

¬ Domínio de proteção: mostra como construir um Domínio de Proteção e quando

uma classe pertence a um Domínio de Proteção;

¬ A classe AccessController: apresenta os conceitos e os propósitos dessa classe;

¬ Testes: mostra alguns testes com aplicações, mostra como configurar os arquivos

de estratégia do Java, descrevendo todos os passos que devem ser seguidos para

executar uma aplicação com segurança.

1.1. PERMISSÕES

O objeto permissão é a base de funcionamento do controle de acesso. É instanciado a

partir da classe Permission (Java.security.Permission), que é uma classe abstrata e é dividida em

subclasses para representar acessos específicos (SUN, 1999). A seguir serão mostradas as principais

classes de permissão.

31

Todas as permissões possuem um tipo que identifica a qual permissão pertence. Por

exemplo, para acessar um arquivo, a permissão terá que ser do tipo java.io.FilePermission; uma

permissão para interagir com soquetes de redes seria java.net.SocketPermission.

Segundo OAKS (1999), um objeto de permissão terá uma permissão concedida, se este

objeto estiver associado com a estratégia de segurança, por um código fonte e por um domínio de

proteção.

A seguir serão apresentados alguns tipos de permissões, porém, não serão mostradas

todas, apenas as mais comuns. O objetivo é mostrar como poderiam ser chamadas essas permissões

quanto a sua sintaxe. São apresentadas as seguintes classes: java.security.Permission,

java.io.FilePermission, java.net.SocketPermission, java.security.BasicPermission e

java.security.AllPermission. As seguintes classes não foram abordadas no trabalho:

PropertyPermission, RunTimePermission, AWTPermission, NetPermission, ReflectPermission e

SerializablePermission.

1.1.1. Java.security.Permission

Esta é a classe abstrata que define as funcionalidades requeridas por todas as permissões.

Cada permissão instanciada é gerada passando um ou mais parâmetros para o construtor,

normalmente são usados dois parâmetros, o primeiro seria target, ou seja, um nome que pode ser o

próprio nome do arquivo para o qual a permissão é garantida, o segundo parâmetro é a ação, por

exemplo, poderia ser simplesmente a ação de ler (read) um arquivo (SUN, 2002).

1.1.2. Java.io.FilePermission

Essa classe é usada quando se deseja fornecer permissões a arquivos. A permissão é

especificada através de nome e ação. O nome é definido pelo diretório e pelo nome do arquivo, que

não pode conter espaços em branco (Ibidem). A Tabela 01 a seguir mostra algumas sintaxes e suas

especificações:

32

Tabela 01 – Sintaxe para convenção dos nomes dos arquivos.

Fonte: (SUN, 2002).

Sintaxe Comentár ios

File Nome do arquivo no diretório atual

Diretório ou / O Diretório atual

Diretório/file Caminho completo onde o arquivo está

gravado

Diretório/* Todos os arquivos desse diretório

* Todos os arquivos do diretório atual

Diretório/- Todos os arquivos no diretório atual e nos

subdiretórios

- Todos os arquivos no sistema de arquivos

abaixo do diretório atual

<<ALL FILES>> Todos os arquivos no sistema de arquivos

É importante ressaltar a diferença entre o uso da sintaxe “ * ” (asterisco) e do “ -” (hífen).

No “* ” somente arquivos que estão dentro desse diretório serão garantidos para as permissões

almejadas, por exemplo: no diretório “c:\Projeto\TCCII \* ” somente os arquivos que estão nesse

diretório terão efeitos da permissão, não sendo possível incluir o arquivo que se encontra em

“c:\Projeto\TCCII \Testes\cadastroalunos.class” . Já “-” fornece permissão a todos os arquivos que

estão no diretório atual e nos diretórios abaixo do atual. Existe notação que se difere bastante dos

outros, a sintaxe “<<ALL FILES>>” , nesse caso, a permissão é fornecida para todos os arquivos

do sistema. Num sistema UNIX, inclui todos os arquivos abaixo do diretório root. Já num sistema

Windows, seriam todos os arquivos de todos os drivers (SUN, 2002).

As ações válidas para essa classe são: ler (read), escrever (write), apagar (delete) e

executar (execute). A Tabela 02 mostra um exemplo simples da construção de um objeto de

permissão.

33

Tabela 02 – Exemplo da construção de um objeto de permissão.

FilePermission Perm1 = new FilePermission(“c: \Projeto\TCCII \* ”, “execute”);

FilePermission Perm2 = new FilePermission(“ -”, “re ad”);

O caminho que especifica o local do arquivo é dependente de plataforma, por isso no caso

da Perm1, o caminho a ser declarado num sistema MS-Windows seria, c:\\Projeto\\TCCII \\* , no

caso de um sistema Unix poderia ser, /Projeto/TCCII /* e num Macintosh seria,

disk:Projeto:TCCII:* , (OAKS, 1999).

1.1.3. Java.net.SocketPermission

Essa classe representa o acesso a redes via soquetes. O nome de uma permissão de soquete

é hostname:port, ou seja, o nome do host e a porta. Cada componente do nome pode ser

representado por um asterisco (* ), (OAKS, 1999). A Tabela 03 mostra como pode ser especificado

um ou mais hosts.

Tabela 03 – Especificação do nome dos hosts.

Fonte: (SUN, 2002).

Sintaxe Comentár ios

Hostname Nome de um único host

200.175.170.1 O endereço IP de um único host

Localhost A máquina local

“ ” Equivalente a localhost

Hostname.domain Um único host dentro de um domínio

* .domain Todos os host em um domínio

* Todos os hosts

Um host pode ser expresso pelo nome DNS, pelo endereço IP ou como localhost ou “ ”

para a máquina local.

34

A nome da porta pode ser especificado para uma única porta ou para uma faixa de portas.

A Tabela 04 mostra como especificar o componente porta.

Tabela 04 – Especificação da porta.

Fonte: (OAKS, 1999).

Sintaxe Comentár ios

P Uma única porta

P- Todas as portas maiores ou iguais a P

-P Todas as portas menores ou iguais a P

P1-P5 Todas as portas entre P1 e P5, inclusive

As ações usando soquetes são: aceitar (accept), conectar (connect), atender (listen) e

resolver (resolve). A ação aceitar é usada pela classe ServerSocket para permitir uma conexão que

chega de um host em particular; conectar é usada pela classe Socket para saber se pode fazer a

conexão com um host em particular; atender é usada pela classe ServerSocket para saber se um

soquete do servidor pode ser criado e resolver é usado pela classe Socket para saber se o endereço

IP de um host em particular pode ser obtido (OAKS, 1999).

A Tabela 05 apresenta alguns exemplos de construção de permissões de soquete.

Tabela 05 – Exemplos de construção de permissões de soquete.

Fonte: (OAKS, 1999).

SocketPermission SP1 = new SocketPermission(“univali.br”, “accept”);

SocketPermission SP2 = new SocketPermission(“200.174.168.1”, “connect”);

SocketPermission SP3 = new SocketPermission(“* .com:80”, “accept”);

SocketPermission SP4 = new SocketPermission(“* .com: -80”, “connect”);

SocketPermission SP5 = new SocketPermission(“* .com:80-”, “accept”);

SocketPermission SP6 = new SocketPermission(“localhost:80”,

“accept,connect,listen”) ;

35

1.1.4. Java.security.BasicPermission

A classe BasicPermission estende a classe Permission, tem seu uso voltado para quem

deseja implementar classes de permissão particular, essa classe implementa uma permissão básica,

ou seja, permissões que não tem nenhuma ação. Conforme OAKS (1999), esse tipo de permissão

pode ser considerada como permissão binária, você as possui ou não. No entanto, essa restrição não

evita que se possam implementar ações nas subclasses da classe BasicPermission. Por exemplo:

“java.lang.RuntimePermission”, “java.security.SecurityPermission”, “java.util .PropertyPermission”

e “java.net.NetPermission (SUN, 2002).

Segundo OAKS (1999), o principal benefício desta classe é a maneira através da qual são

implementados os coringas. O nome das permissões é considerado hierárquico, seguindo uma

convenção separada por pontos. Por exemplo, um conjunto de permissões básicas que a ‘Univali’

queira criar, poderia usar a convenção de que a primeira palavra da permissão será sempre univali:

univali .readDatabase, univali.writeDatabase, univali .folhadepagamento, univali.RH.accessCheck e

assim por diante. OAKS (1999), mostra que essas permissões poderiam ser especificadas por seu

nome completo ou ser especificadas por um coringa asterisco, por exemplo, para coincidir com

todas as permissões apresentadas acima poderia ser usado apenas, ‘univali.* ’ .

Porém, o asterisco não compara os nomes parciais: a permissão ‘univali.write* ’ não

coincidiria com nenhuma permissão mostrada acima. O uso do asterisco deve ser feito sempre na

posição mais a direita, não pode ser usado no começo da permissão e não compara nomes parciais

como no exemplo, respectivamente: * .FolhadePagamento, univali.read* (Ibidem).

A Tabela 06, apresenta os dois construtores necessários para a implementação concreta da

BasicPermission, que chama o construtor da superclasse, pois a classe BasicPermission não possui

um construtor Default.

36

Tabela 06 – Construtores da classe BasicPermission.

Fonte: (OAKS, 1999).

public BasicPermission(String nome) Constrói uma permissão com o nome

especificado, essa é a forma usual o método,

sem nenhuma ação.

public BasicPermission(String nome,

String ação)

Será necessário o uso desse construtor sempre

que for util izado para construir os objetos de

permissão a partir do arquivo Policy.

1.1.5. Java.Secur ity.AllPermission

Segundo OAKS (1999), “Esta classe representa a permissão para realizar qualquer

operação, incluindo arquivo, soquete e outras operações que tenham suas próprias classes de

permissão. Conceder este tipo de permissão é obviamente um tanto quanto perigoso; esta permissão

é usualmente fornecida apenas para as classes na API do Java e para as classes nas extensões Java”.

A forma de construir esse tipo de permissão é mostrado na Tabela 07.

Tabela 07 – Construtor da Classe AllPermission.

Fonte: (OAKS, 1999).

AllPermission ap = new AllPermission Este método não tem nome ou ação

1.2. A ESTRATÉGIA PADRÃO DO JAVA

O Java ao ser instalado configura dois arquivos de segurança para ser usado como padrão

(Default), o “java.policy” e o “java.security”. Porém, esses arquivos têm uma estratégia

insuficiente, ou seja, com o mínimo de segurança, podendo ser alterado ou criado outro arquivo

para ser usado como arquivo de política.

37

Estes arquivos fornecem aos administradores do sistema e aos usuários finais a capacidade

de definirem uma estratégia de segurança para qualquer aplicação ou applet Java. A estratégia usa

os mesmos modelos de permissões visto anteriormente (OAKS, 1999).

Esses arquivos são protegidos e não estão acessíveis aos programadores. A Figura 04

mostra o arquivo “java.policy”, que é instalado como padrão na versão j2sdk 1.4.1. no diretório

“ \j2sdk1.4.1\jre\lib\security” no sistema Windows.

Figura 04 – Arquivo de política padrão “java.policy”

Observa-se na Figura 04, que todas as classes carregadas do diretório de extensões Java,

por exemplo o arquivo “sunjce_provider.jar”, receberá permissão “AllPermission”, ou seja, todas as

permissões. Depois, são definidas permissões para as threads pararem elas mesmas através do

método java.lang.thread.stop(), e recomenda que essa permissão ou seja removida ou sejam

adicionadas restrições a ela. Permite também atender a um soquete com um número de porta maior

ou igual a 1024, ou seja, criar um soquete servidor em uma porta não privilegiada e termina

38

concedendo permissão de leitura às propriedades do sistema listadas para classes que não são do

sistema.

O arquivo de política pode ser alterado conforme necessário, pelo administrador do

sistema ou pode ser adicionado um novo arquivo de política, para isso é necessário que seja

especificado no arquivo de segurança do Java, o “java.security”, conforme a Figura 05.

Na Figura 05, pode-se notar que há duas propriedades do java.policy, na primeira linha,

“pol icy.url.1” é especificado o local do arquivo de política padrão e a segunda linha “policy.url.2”,

especifica onde deverão estar os arquivos de política de cada usuário, porém esses arquivos deverão

ser armazenados com a extensão “.java.policy” na pasta home do usuário.

Figura 05 – arquivo de segurança do Java “java.security”.

1.3. DOMÍNIO DE PROTEÇÃO

Um domínio de proteção representa uma unidade de proteção dentro de um ambiente de

aplicação Java, e está associado normalmente com o conceito de “principal”, onde um principal é

uma entidade em um sistema para a qual as permissões são garantidas (SUN, 2002).

39

Figura 06 – Exemplo de um Domínio de Proteção.

Fonte: (WESTPHALL, 2002).

Conceitualmente um Domínio de proteção engloba um conjunto de classes para as quais

são garantidas as mesmas permissões. Por exemplo: um domínio é identificado pelo CodeSource,

que encapsula duas características, o codebase (uma URL), e um conjunto de certificados para

chaves públicas que correspondem às chaves privadas que assinam todo o código nesse domínio.

Sendo assim, as classes assinadas pelas mesmas chaves de uma mesma URL são colocadas em um

mesmo domínio (Ibidem); a Figura 06 mostra um exemplo.

Portanto, se uma classe tem as mesmas permissões, mas é de uma URL diferente, então

ela pertence a um domínio diferente.

Conforme OAKS (1999), o construtor dessa classe é instanciado da classe

ProtectionDomain (Java.security.ProtectionDomain) e é construído conforme a Tabela 08.

Tabela 08 – Construtor de um Domínio de Proteção.

Fonte: (OAKS, 1999).

public ProtectionDomain(CodeSource cf,

Permissions p)

Constrói um domínio com base no código

fonte e no conjunto de permissões

fornecidas.

�P�����

� P�����

�P�����

� P�����

�P�����

f �� ínio A

f �� ínio B

� ��� ���ões

� ��� ���ões

e ������B�� B� � B

�� ������B� �B�����ção l���

r ��ítica de segurança

40

1.4. A CLASSE AccessController

O controlador de acesso é construído a partir de quatros conceitos:

¬ Código fonte: Representa o local de onde determinadas classes Java foram obtidas;

¬ Permissões: Representa uma solicitação para realizar uma operação em particular;

¬ Estratégia: Representa todas as permissões específicas que devem ser concedidas a

códigos fonte específicos;

¬ Domínio: Representa um código fonte particular e as permissões concedidas a ele.

Conforme OAKS (1999), o método-chave dessa classe obtém uma permissão e determina,

baseado num arquivo de estratégia, se a permissão é concedida ou negada.

Segundo (SUN, 2002), a classe AccessController é usada para três propósitos:

¬ Para decidir se um acesso a um determinado recurso crítico do sistema é permitido

ou negado, dependendo da política de segurança atual;

¬ Marcando um código como privilegiado, afetando assim, as determinações de

acesso subseqüentes, e;

¬ Obter o “ snapshot”, ou seja, o instante em que uma chamada é feita para uma

possível tomada de decisão do controlador de acesso.

A Figura 07 apresenta um trecho de código mostrando um método que chama o

controlador de acesso para saber se a permissão de escrita deverá ser concedida ou negada.

Figura 07 – Exemplo de Controlador de acesso para uma permissão específica.

Fonte: (OAKS, 1999).

41

Na seção seguinte serão analisadas algumas técnicas para se implementar uma boa

estratégia de segurança e serão apresentados testes, mostrando os códigos fontes e seus resultados.

1.5. TÉCNICAS DE IMPLEMENTAÇÃO E TESTES

Este trabalho descreve passos necessários para usar alguns mecanismos de segurança

existentes no modelo Java de segurança. Para limitar o escopo do trabalho, tendo em vista o grande

número de pacotes do modelo de segurança, o trabalho tratou de forma mais específica o uso dos

mecanismos de controle de acesso (SUN, 2002) e também de alguns mecanismos de criptografia

(SUN, 2002).

Códigos fonte são mostrados para explicar passo a passo como utilizar cada um dos

recursos, já que é escassa a bibliografia na área de programação segura que usa os mecanismos de

controle de acesso da linguagem Java.

O objetivo foi a construção de um guia para motivar o uso da segurança na linguagem

Java e também descrever como são usados os mecanismos de controle de acesso e de criptografia na

linguagem.

1.5.1. Aplicação Propr iedadesLocal

A Figura 08, mostra o código fonte de uma aplicação chamada PropriedadesLocal, que

tenta ler os valores de várias propriedades. Esse código fonte não pede nenhuma permissão ao

controlador de acesso para ler essas informações e executa normalmente sem segurança nenhuma.

42

Figura 08 – Código Fonte de uma aplicação que lê várias propriedades locais

Caso esse código seja compilado e executado num ambiente Java, retornará as

propriedades pedidas e algo que pode ser observado é que são informações importantes da máquina

local, que poderiam ser usadas de forma maliciosa por um invasor.

A Figura 09 mostra o código sendo compilado e executado, retornando o valor das

propriedades pedidas.

43

Figura 09 – Código Fonte compilado e executado sem o uso do Controlador de Acesso

O código executado fornece o sistema operacional, a versão do Java, a pasta local do

usuário que está atualmente autenticado no sistema, o local onde a pasta JRE (Java Runtime

Environment) está armazenada e o nome do host e endereço IP respectivamente.

A Figura 10 mostra o mesmo código sendo executado, porém está sendo chamado o

Gerenciador de Segurança para verificar se o código tem direito de acesso aos valores requeridos.

Observa-se que é gerada uma exceção para os três últimos itens, pois o arquivo de permissões

default instalado pelo Java não permite a leitura de tais itens, conforme mostra a Figura 04 anterior.

Figura 10 – Execução da Aplicação PropriedadesLocal de modo seguro.

Já na Figura 11, o mesmo código da Figura 08 foi modificado, criando as permissões

“permissao1” para ler a propriedade “java.home” e a “permissao2” para ler a propriedade

“user.home”. Vale lembrar que isso não garante que o código da Fig ura 11 terá permissão para ler

44

os valores anteriormente negados e sim usará o Controlador de Acesso para verificar se as

permissões requeridas constam no arquivo de política.

Figura 11 – Alterações na Aplicação PropriedadesLocal.

A Figura 12, mostra as novas entradas de permissões no arquivo de política “java.policy”,

garantido que todas as aplicações armazenadas no diretório “C: \ProjetoTeste\ControleDeAcesso”,

terão permissão para ler as propriedades “java.home” e “user.home” do sistema.

45

Figura 12 – Arquivo de política com as novas entradas de permissão.

A Figura 13 mostra o código fonte da Figura 11 executado com o Gerenciador de

Segurança após terem sido adicionadas as entradas no arquivo de política.

Figura 13 – Execução da Aplicação PropriedadesLocal com as alterações.

46

1.5.2. SocketServidor e SocketCliente

Neste teste, foram implementadas duas aplicações usando Socket, um Socket Servidor e

um Socket Cliente. A Figura 14 exibe o código da aplicação SocketServidor comum, ou seja, sem

controlar o acesso.

Essa aplicação cria um Socket servidor na porta 9000, e fica esperando algum cliente

enviar alguma mensagem. Se a tentativa falhar é gerada uma exceção e encerra a conexão. Se um

cliente abrir conexão e enviar alguma mensagem, o SocketServidor imprime a mensagem e volta a

esperar por outra mensagem.

Figura 14 – Aplicação SocketServidor

A Figura 15 apresenta o código de um Socket cliente também na porta 9000 e tenta enviar

uma mensagem e encerra a conexão. Se a tentativa falhar uma exceção será emitida.

47

Figura 15 – Aplicação SocketCliente

As Figuras 16 e 17, mostram as duas aplicações tentando executar chamando o

gerenciador de segurança.

Figura 16 – Execução da Aplicação SocketServidor de modo seguro.

Figura 17 – Execução da Aplicação SocketCliente de modo seguro.

48

A Figura 18, apresenta o código da aplicação SocketServidor com os comandos

adicionados requisitando as permissões ao controlador de acesso, esses comandos adicionais estão

marcados por um retângulo para realçar e ser comparado com o código original. No SocketServidor,

foi criada uma permissão de soquete SP1 para aceitar uma conexão e atender a porta 9000 do

localhost. A linha de comando, “AccessController.checkPermission(SP1), se certificará com o

controlador de acesso se a aplicação SocketServidor tem realmente permissão para isso.

Figura 18 – Alterações na Aplicação SocketServidor.

A Figura 19 mostra a aplicação SocketCliente com os comandos que foram adicionados

para requisitarem permissão de acesso, os comandos adicionais estão ressaltados por um retângulo.

Na aplicação SocketCliente foi criado uma permissão SP2 com permissão para se conectar a porta

9000 do localhost. E como o comando “AccessController.checkPermi ssion(SP2)” foi requisitado ao

controlador de acesso se esta aplicação ter permissão para conectar.

49

Figura 19 – Alterações na Aplicação SocketCliente.

Para finalizar, deve-se adicionar uma entrada ao arquivo de permissões “java.policy”,

fornecendo esse privilégio. A Figura 20 apresenta o arquivo com a entrada marcada com um

retângulo. Observa-se, que foi adicionada apenas uma SocketPermission, mas com as três ações

requeridas pelas duas aplicações.

Figura 20 – Alterações no Arquivo “java.policy”.

50

A Figura 21 mostra a aplicação SocketServidor sendo executada chamando o gerenciador

de segurança, observa-se que inicialmente o Servidor permanece esperando uma mensagem, quando

ocorre de uma mensagem chegar de um cliente, esta mensagem é impressa e o SocketServidor volta

a esperar por outra mensagem.

Figura 21 – Execução da Aplicação SocketServidor com as alterações.

A Figura 22, mostra a aplicação SocketCliente sendo executada com um gerenciador de

segurança. O cliente tenta abrir uma conexão com o servidor, quando isto ocorre, uma mensagem é

enviada, a aplicação SocketCliente avisa que a mensagem foi enviada e fecha a conexão.

Figura 22 – Execução da Aplicação SocketCliente com as Alterações.

1.5.3. Applet AppletTeste

O teste com applet é um programa simples, mas que se usado de maneira maliciosa pode

causar muitos danos. Este applet cria um arquivo em uma pasta desejada. Observe na Figura 23, que

o arquivo que está sendo criado é o arquivo saída.txt, este arquivo possui somente a letra “G”, mas

51

poderia ser um arquivo executável. Porém, a estratégia de segurança padrão do Java não permite

que um applet como esse consiga executar com sucesso.

Figura 23 – Código fonte do Applet AppletTeste.

A Figura 24 mostra o applet AppletTeste tentando ser executado. O controlador de acesso

nega o acesso e gera uma exceção. A Figura 25 mostra a janela do Appletviewer informando que o

applet não pode ser inicializado.

Figura 24 – Execução do applet AppletTeste.

Figura 25 – Execução do AppletTeste mostrado pelo Appletviewer.

O código é então modificado para pedir ao controlador de acesso permissão para escrever

um arquivo. A Figura 26 mostra as modificações feitas no applet com um retângulo em volta.

52

Figura 26 – Alterações no AppletTeste.

É necessário adicionar uma entrada no arquivo de política “java.policy” para que as

modificações feitas no AppletTeste tenham efeito. A Figura 27 mostra como deve ser feita essa

entrada.

Figura 27 – Alterações no Arquivo “java.policy”.

Na Figura 28 o AppletTeste é executado com o gerenciador de segurança e não gera

nenhuma exceção. A Figura 29 mostra a janela do Appletviewer sendo executado normalmente.

53

Figura 28 – Execução do AppletTeste com as Alterações.

Figura 29 – Execução do AppletTeste alterado mostrado pelo Appletviewer.

Na Figura 30, pode-ser observar que o arquivo saída.txt foi realmente criado, A Figura 31

mostra o arquivo criado contendo a letra “G” .

Figura 30 – Pasta TesteApplet.

54

Figura 31 – Arquivo saída.txt.

2. CRIPTOGRAFIA

Após ter examinado os recursos de segurança do Java, basicamente o modelo caixa de

areia, irá ser apresentado os recursos criptográficos da linguagem Java. Conforme OAKS (1999),

este pacote é um conjunto de classes que foram introduzidos ao Java Versão 1.1 e posteriormente

expandidas para a versão 1.2, fornecendo camadas adicionais de segurança além das já vistas no

capítulo anterior.

Um dos objetivos deste trabalho não é mostrar profundamente a teoria da criptografia e

sim explicar os conceitos básicos para que se possa fazer uso das APIs envolvidas.

Neste capítulo serão apresentados as duas APIs envolvidas na criptografia, o JCA e o JCE,

mostrando suas características, em seguida serão apresentados testes para validação dos modelos.

2.1. JAVA CRYPTOGRAPHY ARCHITECTURE (JCA)

O JCA é uma arquitetura ou framework de acesso e desenvolvimento de funcionalidades

criptográficas, isso inclui Assinatura digital e Message Digest, no Java 2 SDK o JCA foi

significativamente expandida para suportar o gerenciamento de certificados tal como X.509 versão

3, e introduziu uma nova arquitetura de segurança Java para controle de acesso extensivo, flexível,

altamente configurável e grão-fino (SUN, 1999).

Conforme (SUN, 1999), o JCA foi desenvolvido a partir dos seguintes princípios:

55

¬ I ndependência de implementação: é alcançada usando um provedor de serviços

criptográficos baseado na arquitetura, CSP (Cryptographic Service Provider) ou

simplesmente provider. Referencia um pacote ou um conjunto de pacotes que

implementam um ou mais serviços criptográficos, tais como, assinatura digital e

message digest.

¬ I ndependência de Algor itmo: é alcançada através da definição dos tipos de

“serviços” (engines) criptográficos, e definem classes que fornecem as

funcionalidades criptográficas. Essas classes são chamadas engine classes, como

exemplos têm-se: MessageDigest, Signature e KeyFactory.

¬ I nteroperabilidade de implementação: significa que várias implementações

podem trabalhar umas com as outras, usando uma outra chave, ou verificando uma

ou outra assinatura, ou seja, várias implementações podem trabalhar

conjuntamente sem nenhuma carga ou dificuldade para o desenvolvedor.

¬ Extensibil idade de Algor itmo: significa que novos algoritmos que são suportados

pelas classes engines podem ser facilmente adicionados.

Para que se possa obter um melhor entendimento sobre o JCA, torna-se necessário uma

abordagem mais detalhada sobre o CSP, mais comumente chamado de provider. O provider é um

pacote ou conjunto de pacotes, para suprir uma implementação concreta de subclasses de aspectos

criptográficos da API de segurança do Java (Ibidem), como algoritmos de assinatura digital,

algoritmos de hash (que será abordado no tópico Message Digest), entre outros.

O JRE da SUN microsystems possui seu próprio provedor padrão, chamado “SUN”, que

fornece uma série de serviços que estão listados abaixo (SUN, 1999):

¬ Uma implementação de algoritmo de assinatura digital (DSA);

¬ Uma implementação de algoritmos de Messagem Digest MD5 e SHA-1;

¬ Um DSA Key Pair Generator que gera um par de chaves pública e privada para

algoritmos DSA;

¬ Um gerador de parâmetros de algoritmos DSA;

¬ Um gerenciador de parâmetros de algoritmos DSA;

¬ Um “key factory” DSA fornecendo conversões bi -direcionais;

¬ Uma implementação de propriedade “SHA1PRNG”, algoritmo de geração de

números pseudo-randômicos seguindo as recomendações do IEEE;

56

¬ Um gerador de certificados “certificate factory” para certificados X.509;

¬ E uma implementação de um Keystore (que será explicado a seguir).

Pode-se implementar um provider particular que poderá ser usado, que deverá ser

especificado no arquivo de segurança (java.security) conforme mostra a Figura 32. Porém, essa

abordagem não faz parte dos objetivos do presente trabalho, por isso, não será tratado.

Figura 32 – Arquivo java.security mostrando a lista de provedores.

As principais classes e interfaces do JCA encontram-se no java.security,

java.security.spec, java.security.interface. Porém serão abordadas apenas as classes Provider,

Security, MessageDigest, Signature, AlgorithmParameter, KeyFactory, CertificateFactory,

KeyPairGenerator, Keystore e SecureRandom.

2.1.1. Classe Provider

Essa classe, segundo OAKS (1999), forma a base da arquitetura do provedor de segurança.

O termo CSP é usado para referenciar um pacote ou um conjunto de pacotes que suprem

uma implementação concreta de um subconjunto de aspectos criptográficos da

API de segurança do Java 2 SDK. A classe Provider é uma interface para tal pacote ou conjunto de

pacotes, e tem métodos para acessar o nome do provedor, número da versão, e outras informações

(SUN, 1999).

57

A classe Provider é raramente usada diretamente por programadores, como podem ser

observados os métodos são altamente informativos e devem ser usados de acordo. A Tabela 09

mostra como deve ser feita a utilização desses métodos (OAKS, 1999).

Tabela 09 – Métodos da Classe Provider.

Fonte: (OAKS, 1999).

public String getName() Retorna o nome do provedor.

public double getVersion() Retorna o número da versão do provedor.

public String getInfo() Retorna a String de informações do

provedor.

public String toString() Retorna a String que especifica o provedor,

geralmente o nome do provedor

concatenado ao número da versão do

provedor.

2.1.2. Classe Security

A Classe Security é responsável por gerenciar o conjunto de classes provider que um

programa Java pode utilizar e forma a última ligação na arquitetura do provedor de segurança. Essa

classe jamais poderá ser criada ou colocada em uma subclasse, ela é uma classe final e todos os seus

métodos são static, exceto o construtor que é privado, ou seja, ela existe somente para fornecer um

local para que sejam guardados os métodos que lidam com o pacote java.security (OAKS, 1999).

Caso seja implementado um provedor particular, este pode ser adicionado ao arquivo

java.security de forma programática, porém, segundo (SUN, 1999), os métodos para adicionar ou

remover provedores pode ser executado somente por um programa confiável. Um programa é

confiável se uma aplicação local não executa abaixo do gerenciador de segurança, ou se um applet

ou aplicação tenham permissão para executar o método específico.

Como pode ser visto na Figura 32, os provedores listados no arquivo de segurança do Java

são mantidos em array indexado. Quando a classe security é solicitada a fornecer um algoritmo

particular para uma operação, o array é pesquisado seqüencialmente para obter o provedor que

58

possa fornecer o algoritmo solicitado para a operação solicitada (OAKS, 1999). A Tabela 10,

mostra os métodos para adicionar um provedor no arquivo java.security.

Tabela 10 – Métodos para adicionar um provedor à lista de provedores.

Fonte: (SUN, 1999).

public static int addProvider(Provider

provedor)

Adiciona um novo provedor na última

posição do array da lista de provedores.

public static int insertProviderAt(Provider

provedor, int posição)

Adiciona um novo provedor á lista de

provedores na posição especificada, se este

não for o último da lista, os outros índices

serão mudados para criar o espaço

necessário.

2.1.3. Classe MessageDigest

A Classe MessageDigest é uma classe engine designada para fornecer funcionalidades de

Message Digest criptográficamente segura, tais como SHA-1 ou MD5. Uma Message Digest possui

uma entrada de tamanha arbitrária (um array de bytes) e gera uma saída de tamanha fixo, chamada

digest ou hash (SUN, 1999).

Uma hash é um pequeno trecho de texto gerado para representar um texto maior. A idéia é

que não existam textos que gerem mesmos hashes, de forma que uma hash seja capaz de validar a

integridade de uma mensagem (Ibidem), ou seja, uma hash irá garantir somente que o texto não foi

modificado em trânsito, mas não assegura que ninguém tenha lido esse texto.

Logicamente nada assegura que um interceptador altere o texto em trânsito e gere um

novo hash e envie ao destino original, que ao receber a mensagem irá gerar um hash a partir do

texto recebido irá comparar com o hash que recebeu com a mensagem. Por isso é importante enviar

o hash de uma mensagem da maneira mais segura possível.

A Tabela 11 mostra os principais métodos da Classe MessageDigest.

59

Tabela 11 – Principais métodos da Classe MessageDigest

Fonte: (SUN, 1999).

public static MessageDigest getInstance

(String algoritmo)

Cria um objeto MessageDigest com o

algoritmo especificado.

public static MessageDigest getInstance

(String algoritmo, String provedor)

Cria um objeto MessageDigest com o

algoritmo e o provedor especificado.

public byte[] digest() Retorna o hash calculado.

public byte[] digest(byte[] input) Retorna o hash calculado para uma entrada

específica.

public int digest(byte[] buf, int offset, int

len)

Retorna o hash armazenado em um buffer

buf, é inicializado por offset e o número de

bytes alocado para o buffer é o len.

2.1.4. Classe Signature

A Classe Signature fornece algoritmos de assinatura digital criptográficos, tais como DSA

ou RSA com MD5. Um algoritmo de assinatura digital tem uma entrada de tamanho arbitrário e

uma chave privada e gera uma string de bytes relativamente curta, denominada assinatura, que

possui as seguintes propriedades (SUN, 1999):

¬ Dado a chave pública correspondendo a chave privada usada para gerar a

assinatura, deverá ser possível verificar a autenticidade e a integridade da entrada;

¬ A assinatura e a chave pública não poderão revelar nada a respeito da chave

privada.

Um objeto Signature pode ser usado para assinar dados, pode também verificar se uma

assinatura alegada é de fato a assinatura autêntica dos dados associados a ela (Ibidem).

Existem três estados de objeto Signature segundo (SUN, 1999):

¬ UNINITIALIZED;

¬ SIGN;

¬ VERIFY.

60

Quando um Objeto Signature é criado, seu estado é UNINITIALIZED. Posteriormente, a

classe Signature define dois métodos de inicialização: initSign e initVerify, que trocam o estado do

objeto para SIGN e VERIFY respectivamente (Ibidem).

Como toda classe engine, para criar um objeto Signature é necessário criar uma instância

da classe Signature, chamando o método static getInstance. A Tabela 12, mostra como chamar

esses métodos (OAKS, 1999).

Tabela 12 – Métodos para gerar um objeto de assinatura.

Fonte: (SUN, 1999).

public static Signature getInstance(String

algoritmo)

Gera um objeto de assinatura que

implementa o algoritmo dado.

public static Signature getInstance(String

algoritmo, String provedor)

Gera um objeto de assinatura que

implementa o algoritmo dado, porém o

sistema irá pesquisar o algoritmo apenas no

provedor especificado.

Entretanto o objeto ainda está no estado UNINITIALIZED e deverá ser inicializado. Isso

dependerá se o objeto será usado primeiro para criar uma assinatura ou para verificar uma

assinatura.

A Tabela 13, exibe os métodos que deverão ser chamados para inicializar um objeto

Signature.

Tabela 13 – Métodos para inicializar um Objeto Signature.

Fonte: (SUN, 1999).

public final void initSign(PrivateKey

chaveprivada)

Inicializa o objeto Signature, preparando-o

para criar uma assinatura. Colocando no

estado SIGN.

public final void initVerify(PublicKey

chavepublica)

Inicializa o objeto Signature, preparando-o

para verificar uma assinatura. Colocando no

estado VERIFY.

61

Os métodos apresentados na Tabela 14 podem ser usados tanto no estado SIGN como no

estado VERIFY, e ambos têm que ter sido inicializados (Ibidem).

Tabela 14 – Métodos para adicionar dados ao objeto.

Fonte: (OAKS, 1999).

public final void update(byte b)

public final void update(byte [] data)

public final void update(byte [] data, int off ,

int len)

Adiciona os dados fornecidos aos dados

acumulados que o objeto irá eventualmente

assinar ou verificar.

Os métodos para gerar a assinatura e verificar uma assinatura são mostrados

respectivamente na Tabela 15, conforme (SUN, 1999).

Tabela 15 – Métodos para Gerar e Verificar Assinaturas.

Fonte: (OAKS, 1999).

public final byte[] sign() Retorna o resultado da assinatura em um

array de bytes.

public final int sign(byte[] outbuf, int offset,

int len)

Armazena o resultado da assinatura em um

buffer outbuf fornecido, começando em

offset. O número de bytes em outbuf é dado

por len. Este método retorna o número de

bytes armazenados.

public final Boolean verify(byte[]

encodedSignture)

O argumento deve ser dado por um array de

bytes contendo a assinatura codificada.

2.1.5. Classe AlgorithmParameter

2.1.5.1. Classes e Interfaces para Especificação dos parâmetros do Algoritmo

“Uma especificação do parâmetro de algoritmo é uma representação transparente do

conjunto de parâmetros usados com o Algoritmo” (SUN, 1999).

62

Uma representação transparente de um conjunto de parâmetros significa que pode-se

acessar cada valor do conjunto de parâmetro individualmente. Isso contrasta com uma

representação opaca, onde não se tem acesso direto aos campos dos parâmetros, podendo somente

conseguir o nome do algoritmo associado com o conjunto de parâmetros e algum tipo de

codificação do conjunto de parâmetros (Ibidem).

A interface do AlgorithmParameterSpec é uma especificação transparente dos parâmetros

criptográficos. Essa interface não contém métodos nem constantes. Seu propósito é somente agrupar

todos as especificações de parâmetros (Ibidem).

2.1.5.2. Classe AlgorithmParameter

Essa é uma Classe engine que fornece uma representação opaca dos parâmetros

criptográficos, Entretanto, pode-se chamar o método getParameterSpec para converter um objeto

AlgorithmParameters para uma especificação transparente (SUN, 1999).

A Tabela 16, resume os passos para criar, inicializar um objeto AlgorithmParameters,

obter o parâmetro codificado, e converter um objeto AlgorithmParameters para uma especificação

transparente.

Tabela 16 – Métodos da Classe AlgorithmParameter.

Fonte: (SUN, 1999).

public static AlgorithmParameters

getInstance (String algoritmo)

Cria um objeto AlgorithmParameters

public static AlgorithmParameters

getInstance (String algoritmo, String

provedor)

Cria um objeto AlgorithmParameters

especificando o nome do provedor.

public void init (AlgorithmParameterSpec

paramspec)

Após ter sido instanciado, o objeto deve ser

inicializado, nesse caso usando uma

especificação de parâmetro apropriada.

public void init (byte[] params) Inicializa o objeto com um array contendo

os parâmetros codificados.

63

public void init (byte[] params, String

formato)

Inicializa o objeto com um array contendo

os parâmetros codificados e o formato para

decodificação.

public byte[] getEncoded() Retorna o parâmetro em seu formato de

codificação primário.

public byte[] getEncoded(String formato)

Retorna o parâmetro em um formato de

codificação especificado.

public AlgorithmParameterSpec

getParameterSpec (Class paramSpec)

Converte um objeto AlgorithmParameters

em uma especificação transparente.

2.1.6. Classe KeyFactory

Segundo (SUN, 1999), a classe KeyFactory é designada para fornecer conversões entre

chaves criptográficas opacas e especificação de chaves, ou seja, representações transparentes. Key

Factories são bidirecionais, isto é, construir um objeto de chave opaca de uma especificação de

chave dada ou recuperar um objeto de chave em um formato desejado.

Em contrapartida, OAKS (1999), afirma que a classe KeyFactory é usada para importar e

exportar chaves. Como a API da SUN é mais atualizada será seguida neste tópico.

A Tabela 17, apresenta os métodos usados para criar um objeto KeyFactory (SUN, 1999).

Tabela 17 – Método para criação do Objeto KeyFactory.

Fonte: (SUN, 1999).

public static KeyFactory getInstance(String

Algoritmo)

Cria o objeto KeyFactory de acordo com o

algoritmo especificado

public static KeyFactory getInstance(String

Algoritmo, String provedor)

Cria o objeto KeyFactory de acordo com o

algoritmo especificado e garante que a

implementação é do provedor requerido.

A Tabela 18 mostra a conversão bi-direcional entre uma especificação de chave e um

objeto de chave. Os dois primeiros métodos convertem uma especificação de chave em uma chave

64

pública ou privada e no terceiro método converte a chave em uma especificação de chave, o

KeySpec identifica a classe de especificação na qual a chave irá retornar.

Tabela 18 – Conversão entre um objeto chave e uma especificação de chave.

Fonte: (SUN, 1999).

public PublicKey generatePublic(KeySpec

keySpec)

Obtém um objeto PublicKey opaco da

especificação.

public PrivateKey generatePrivate(KeySpec

keySpec)

Do mesmo modo obtém um objeto

PrivateKey opaco da especificação.

public KeySpec getKeySpec(Key chave,

Class KeySpec)

Se tiver um objeto Key, pode-se conseguir

um objeto de especificação Key

correspondente.

2.1.7. Classe CertificateFactory

Essa classe é usada para gerar certificados e CRL (Certificate Revocation List). A Tabela

19, exibe no primeiro e segundo método, como criar um objeto CertificateFactory, em seguida são

apresentados os métodos para gerar objetos certificados e objetos CRL, respectivamente (SUN,

1999).

Tabela 19 – Cria e Gera objetos Certificate e CRL.

Fonte: (SUN, 1999).

public static CertificateFactory

getInstance(String tipo)

Cria um objeto CertificateFactory, o tipo

determinará se será criado um certificado ou

um CRL

public static CertificateFactory

getInstance(String tipo, String provedor)

Cria um objeto CertificateFactory, o tipo

determinará se será criado um certificado ou

um CRL e opcionalmente pode-se escolher

o provedor

public final Certificate

generateCertificate(InputStream inStream)

Gera um objeto Certificate e inicilaliza-o

com leitura de dados de entrada.

65

public final Collection

generateCertificate(InputStream inStream)

Retorna uma coleção de certificados,

possivelmente vazia, para leitura dos dados

de entrada.

public final CRL generateCRL

(InputStream inStream)

Cria um objeto CRL e inicializa com leitura

dos dados de entrada.

public final Collection generateCRL

(InputStream inStream)

Retorna uma coleção de certificados,

possivelmente vazia, para leitura dos dados

de entrada.

2.1.8. Classe KeyPairGenerator

A Classe KeyPairGenerator é uma classe engine usada para gerar pares de chaves pública

e privada. Há modos de criar um par de chaves: usando um algoritmo de maneira independente e

um algoritmo de maneira específica. A única diferença entre eles é a inicialização do objeto

(Ibidem).

Toda geração de par de chaves é feita com um KeyPairGenerator, isso é feito usando os

métodos apresentados nas Tabela 20.

Tabela 20 – Gera pares de chaves pública e privada.

Fonte: (SUN, 1999).

public static KeyPairGenerator

getInstance(String algoritmo)

Gera pares de chaves com o algoritmo

denominado.

public static KeyPairGenerator

getInstance(String algoritmo, String

provedor)

Gera pares de chaves com o algoritmo

denominado e com o provedor específico.

Um gerador de par de chaves para um algoritmo particular e cria um par de chaves para

ser usado com esse algoritmo, e também associa os parâmetros específicos do algoritmo com cada

uma das chaves geradas (SUN, 1999).

66

Um gerador de par de chaves precisa ser inicializado antes de poder criar o par de chaves.

Na maioria dos casos pode-se inicializar com um algoritmo independente, porém em alguns casos

torna-se necessário a inicialização por um algoritmo específico (Ibidem).

2.1.8.1. Inicialização com Algoritmo Independente

Nesta inicialização todo gerador de par de chaves compartilha um tamanho de chave e

uma fonte randômica. O tamanho da chave é interpretado diferentemente para algoritmos diferentes.

O método de inicialização possui dois tipos de argumentos conforme mostra a Tabela 21 (Ibidem).

Tabela 21 – Inicializa o KeyPairGenerator para um algoritmo independente.

Fonte: (SUN, 1999).

public void initialize (int keysize,

SecureRandom random)

Inicializa o KeyPairGenerator com um

tamanho de chave especificado em keysize e

um número randômico.

public void initialize (int keysize) Inicializa o KeyPairGenerator somente com

um tamanho de chave especificado em

keysize e usa uma fonte randômica do

próprio sistema.

Pode-se usar como exemplo, o algoritmo DSA. Para o algoritmo DSA o tamanho da chave

corresponde ao tamanho do módulo e o tamanho do módulo para algoritmos DSA pode ser 512, 768

ou 1024 (SUN, 1999).

2.1.8.2. Inicialização com Algoritmo Específico

Para situação onde um conjunto de parâmetro de um algoritmo específico já existe, há dois

métodos de inicialização que possuem um argumento AlgorithmParameterSpec, segundo mostra a

Tabela 22 (Ibidem).

67

Tabela 22 - Inicializa o KeyPairGenerator para um algoritmo Específico.

Fonte: (SUN, 1999).

public void initialize

(AlgorithmParameterSpec parametro,

SecureRandom random)

Inicializa o KeyPairGenerator com uma

especificação de parâmetros de algoritmo e

gera um número randômico.

public void initialize

(AlgorithmParameterSpec parâmetro)

Inicializa o KeyPairGenerator com uma

especificação de parâmetros de algoritmo

usa uma fonte randômica do próprio

sistema.

Após inicializar o KeyPairGenerator, pode-se gerar o par de chaves que será sempre o

mesmo independente da forma de incialização. O método para gerar o par de chaves é mostrado na

Tabela 23 (Ibidem).

Tabela 23 – Método para construir um par de chaves

public Keypair generateKeyPair() Gera um par de chaves pública e privada

2.1.9. Classe Keystore

Keystore é um banco de dados que pode ser usado para gerenciar um repositório de

chaves e certificados. Um certificado é uma declaração assinada digitalmente por um entidade,

dizendo que a chave pública de uma outra entidade tem um valor particular (Ibidem).

A Classe KeyStore possui uma interface bem definida para acessar e modificar

informações nela contidas. Essa classe representa uma coleção de chaves e certificados, além de

gerenciar dois tipos de entrada (Ibidem).

2.1.9.1. Entrada de Chave

Este tipo de entrada possui informações sobre a chave criptográfica muito importantes,

que são armazenadas em um formato protegido para prevenir acessos não autorizados.

68

Normalmente, uma chave armazenada nesse tipo de entrada é uma chave secreta ou uma chave

privada acompanhada de uma cadeia de certificados autenticando a chave pública correspondente

(Ibidem).

2.1.9.2. Entrada de Certificado Confiável

Este tipo de entrada contém um único certificado de chave pública pertencente à outra

parte. Este é chamado de Certificado Confiável porque o próprio KeyStore confia que a chave

pública no certificado realmente pertence a quem diz ser. Pode ser usada para autenticar a outra

parte (Ibidem).

Cada entrada em um keyStore é identificada por uma String “alias”, independente do tipo

de entrada utilizado. A Tabela 24 exibe os principais métodos do KeyStore, como criar um objeto

KeyStore, carregar um KeyStore particular, conseguir uma lista de Aliases do KeyStore, determinar

o tipo de entrada, adicionar/configurar/remover entradas, conseguir informações e salvar um

KeyStore (Ibidem).

Tabela 24 - Principais métodos do KeyStore.

Fonte: (SUN, 1999).

public static KeyStore getInstance(String

tipo)

Cria um KeyStore com o tipo especifico.

public static KeyStore getInstance(String

tipo, String provedor)

Cria um KeyStore com o tipo especifico e

especificado também o provedor que

implementa o tipo requerido.

public final void load(InputStream stream,

String senha)

Antes do KeyStore ser usado, este precisa

ser carregado na memória, a senha é

opcional, mas é usado para checar a

integridade dos dados do KeyStore.

public final Enumeration aliases() Retorna uma lista de aliases no KeyStore.

public final boolean isKeyEntry(String

alias)

Determina se o tipo de entrada do alias

especifico é uma chave

69

public final boolean

isCertificateEntry(String alias)

Determina se o tipo de entrada do alias

especifico é um certificado.

public final void setCerticateEntry(String

alias, Certificate cert)

Se o alias não existe, uma entrada de

certificado confiável é criada. Se já existe é

apenas associado as certificado cert.

public final void setKeyEntry(String alias,

key chave, String senha, Certificate[] chain)

Nesse método a chave é protegida pela

senha.

public final void setKeyEntry(String alias,

byte[] chave, Certificate[] chain)

Nesse método a chave é protegida pelo

array de bytes.

public final void deleteEntry(String alias) Remove a entrada do KeyStore

public final Key getKey(String alias, String

senha)

Retorna a chave associada ao alias

especificado

public final Certificate getCertificate(String

alias)

Retorna o certificado associado ao alias

especificado

public final Certificate[]

getCertificateChain(String alias)

Retorna a cadeia de certificado associada ao

alias especificado

public final String

getCertificateAlias(Certificate cert)

Determina o nome (alias) da primeira

entrada no certificado

public final void store(OutputStream

stream, String senha)

Salva o KeyStore que está em memória, a

senha é usada para calcular o checksun dos

dados do KeyStore.

2.1.10. Classe SecureRandom

Esta classe fornece funcionalidades para gerar números randômicos. A Tabela 25

apresenta os principais métodos desta classe (Ibidem).

Tabela 25 – Principais métodos da classe SecureRandom.

Fonte: (SUN, 1999).

public static SecureRandom

getInstance(String algoritmo)

Cria um objeto SecureRandom para com um

algoritmo específico

70

public static SecureRandom

getInstance(String algoritmo, String

provedor)

Cria um objeto SecureRandom para com

uma algoritmo e um provedor específico

syncronized public void setSeed(byte[]

seed)

Gera um byte para ser usado como semente

na geração de um número randômico

syncronized public void nextBytes(bytes[]

bytes)

Usado para gerar bytes randômicos de

qualquer tamanho

public byte[] generateSeed(int numBytes) Fornece um número para ser usado como

byte semente para gerar um número

randômic

2.2. JAVA CRYPTOGRAPHY EXTENSION (JCE)

O JCE (Java Cryptography Extension) estende a API do JCA para incluir APIs para

cifragem, troca de chaves e código de autenticação de mensagem MAC (Message Authentication

Code) (SUN, 1999).

O JCE era inicialmente um pacote opcional, extensão para as versões 1.2.x e 1.3.x do Java

2 SDK, entretanto, a partir da versão 1.4 este foi integrado e passou a fazer parte do Java 2 SDK

(SUN, 2002).

O Java 2 SDK 1.4, traz como padrão um provedor JCE chamado “SunJCE” como pode ser

observado na Figura 33, que é instalado e registrado no arquivo java.security.

Figura 33 – Provedor JCE pré-instalado no arquivo java.security

71

Conforme (SUN, 2002), a principal diferença entre o JCE 1.2.x e o JCE integrado ao Java

2 SDK 1.4, é que agora o JCE já é exportável para muitos países, anteriormente somente os Estados

Unidos e Canadá poderiam implementar essa API de uma forma mais rigorosa.

As principais classes e interfaces do JCE encontram-se nos pacotes: javax.crypto,

javax.crypto.spec e javax.crypto.interface e são: Cipher, MAC, KeyGenerator, KeyAgreement e

SealedObject, que estão descritas a seguir (SUN, 2002).

2.2.1. Classe Cipher

A Classe Cipher fornece as funcionalidades criptográficas usadas para cifrar e decifrar

dados, formando o núcleo do JCE (SUN, 2002).

Como toda classe engine da API, para criar-se um objeto cipher é necessário o uso do

método getInstance da classe cipher. Este método é estático e retorna uma instância da classe, no

caso da classe cipher, uma instância que implementa uma transformação requisitada, por isso, deve-

se especificar o nome da transformação e opcionalmente um provedor para implementar essa

transformação (Ibidem).

Segundo (SUN, 2002), uma transformação é uma String que descreve uma operação ou

um conjunto de transformações, para ser desenvolvida numa entrada dada, produzindo alguma

saída. Isto inclui um nome de um algoritmo de criptografia, e pode ser seguido por um modo e um

padding. A Tabela 26, mostra como criar um objeto Cipher e modelos de transformação.

Tabela 26 – Métodos para criar objetos Cipher.

Fonte: (SUN, 1999).

public static Cipher getInstance(String

algoritmo);

Cria um objeto Cipher sem um provedor

específico.

public static Cipher getInstance(String

algoritmo, String provedor);

Cria um objeto Cipher especificando o

provedor e o algoritmo de transformação.

Cipher c1 = Cipher.getInstance

(“DES/ECB8/PCKS5Padding”);

Algoritmo DES em modo CFB de 8 bits e um

esquema de padding PCKS5Padding

72

Cipher c1 = Cipher.getInstance

(“DES/OFB32/NoPadding”);

Cria um objeto Cipher com algoritmo DES em

modo OFB de 32 bits e sem padding.

Um objeto cipher deve ser inicializado, cada método deve ter um parâmetro modo e outro

parâmetro que inicializa o modo, a Tabela 27 mostra os principais métodos de inicialização da

classe cipher. Esse modo pode ser referenciado por um nome simbólico como a seguir e uma breve

descrição de cada modo (Ibidem):

¬ ENCRYPT_MODE: cifra dados;

¬ DECRYPT_MODE: decifra dados;

¬ WRAP_MODE: envolve uma chave em bytes para que seja transportada

seguramente;

¬ UNWRAP_MODE: operação contrária do modo anterior.

Tabela 27 – Métodos para inicializar um objeto Cipher.

Fonte: (SUN, 1999).

public void init(int modo, key chave);

public void init(int modo, Certificate certificado);

public void init(int modo, key chave, SecureRandom sr);

public void init(int modo, Certificate certificado, SecureRandom sr);

public void init(int modo, key chave, algorithmParameterSpec parametro);

public void init(int modo, key chave, algorithmParameterSpec parametro, SecureRandom

sr);

public void init(int modo, key chave, algorithmParameters parametros);

public void init(int modo, key chave, algorithmParameters parametros, SecureRandom sr);

Conforme (SUN, 2002), um dado pode ser cifrado e decifrado de duas formas, em uma

única operação ou em múltiplas operações. Para dados com tamanho conhecido e pequeno pode ser

feita uma operação, no caso de não se saber com antecedência o quanto de dado virá e se poderá ser

armazenado em memória de uma só vez, é aconselhável cifrar ou decifrar em múltiplas operações.

Para cifrar ou decifrar um dado, chama-se um método doFinal, como apresenta a Tabela

28. Para cifrar e decifrar em múltiplas operações chama-se um método update e chama-se um

método doFinal para finalizar como mostra a Tabela 29 (Ibidem).

73

Tabela 28 – Métodos para cifrar e decifrar dados em uma única operação.

Fonte: (SUN, 1999).

public byte[] doFinal(byte[] input);

public byte[] doFinal(byte[] input, int inputOffset, int inputLen);

public int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output);

public int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int

outputOffset);

Tabela 29 – Métodos para cifrar e decifrar dados em múltiplas operações.

Fonte: (SUN, 1999).

public byte[] update(byte[] input);

public byte[] update(byte[] input, int inputOffset, int inputLen);

public int update(byte[] input, int inputOffset, int inputLen, byte[] output);

public int update(byte[] input, int inputOffset, int inputLen, byte[] output, int

outputOffset);

Quando um objeto Cipher é inicializado usando o modo WRAP_MODE, a chave usada

para cifrar algum dado fica protegida para ser transportada de um lugar a outro. Ao chegar ao seu

destino, o receptor precisará de algumas informações adicionais para usar o modo

UNWRAP_MODE, como o nome do algoritmo da chave e o tipo de chave envolvida, que pode ser:

Cipher.SECRET_KEY, Cipher.PRIVATE_KEY ou Cipher.PUBLIC_KEY. E não precisa ser

especificado quando está chamando o método com o modo WRAP_MODE. A Tabela 30 mostra os

métodos para proteger a chave e para ter a chave original novamente (Ibidem).

Tabela 30 – Método para proteger uma chave e obtê-la novamente.

Fonte: (SUN, 1999).

public final byte[] wrap(Key chave);

public final Key unwrap(byte[] wrappedKey, String AlgoritmowrappedKey, int

tipowrappedKey);

74

2.2.2. Classe MAC

A Classe MAC fornece funcionalidades para um código de autenticação de mensagens.

Um MAC pode ser computado em uma única operação ou em múltiplas operações, como para cifrar

e decifrar dados na Classe Cipher. Os principais métodos desta classe são apresentados na Tabela

31 (SUN, 2002).

Tabela 31 – Principais métodos da Classe MAC.

Fonte: (SUN, 1999).

public static Mac getInstance(String

algoritmo);

Cria um objeto MAC para o algoritmo

especificado.

public static Mac getInstance(String

algoritmo, String provedor);

Cria um objeto MAC para o algoritmo e um

provedor especificado.

public void init (Key chave); Inicializa o objeto MAC com a chave

secreta especificada.

public void init (Key chave,

AlgorithmParameterSpec parametros);

Inicializa o objeto MAC com a chave

secreta e um conjunto de parâmetros

especificados.

public byte[] doFinal(byte[] input); Computa algum dado em uma única

operação.

public void update(byte input); Computa algum dado em múltiplas

operações, e deve ser finalizado com o

método doFinal.

public void update(byte[] input); Computa algum dado em múltiplas

operações, e deve ser finalizado com o

método doFinal.

public void update(byte[] input, int

inputOffset, int inputLen);

Computa algum dado em múltiplas

operações, e deve ser finalizado com o

método doFinal.

75

2.2.3. Classe KeyGenerator

A classe KeyGenerator é usada para criar chaves secretas para algoritmos simétricos.

Como em outra classe engine um objeto da classe é criado, em seguida inicializado para depois

poder gerar uma chave secreta, a Tabela 32 mostra os principais métodos dessa classe (SUN, 2002).

Tabela 32 – Principais Métodos da Classe KeyGenerator.

Fonte: (SUN, 1999).

public static KeyGenerator

getInstance(String algoritmo);

Cria um objeto da Classe KeyGenerator

com um algoritmo simétrico específico.

public static KeyGenerator

getInstance(String algoritmo, String

provedor);

Cria um objeto da Classe KeyGenerator

com um algoritmo simétrico e um provedor

específico.

public void init (int keysize); Inicializa o objeto KeyGenerator de uma

maneira independente de algoritmo e com

um tamanho de chave específico e uma

fonte randômica do próprio sistema.

public void init (SecureRandom sr); Inicializa o objeto KeyGenerator de uma

maneira independente de algoritmo e com

uma fonte randômica específica.

public void init (int keysize, SecureRandom

sr);

Inicializa o objeto KeyGenerator de uma

maneira independente de algoritmo e com

um tamanho de chave e uma fonte

randômica específicos.

public void init (AlgorithmParameterSpec

parametros);

Inicializa o objeto KeyGenerator com

algoritmo específico.

public void init (AlgorithmParameterSpec

parâmetros, SecureRandom sr);

Inicializa o objeto KeyGenerator com

algoritmo específico e uma fonte randômica

específicos.

public SecretKey generateKey(); Gera uma chave secreta.

76

2.2.4. Classe KeyAgreement

A classe KeyAgreement fornece as funcionalidades de um protocolo de concordância de

Chaves. As chaves envolvidas são criadas por um gerador de chaves e tem que criar um objeto

KeyAgreement. Essa concordância de chaves é feita em fases, usando um método doPhase( ); todo

protocolo de concordância de chaves consiste num número de fases que precisam ser executadas

por cada parte envolvida. Depois das fases estarem completas, usa-se o método generateSecret( ),

para calcular a chave compartilhada. A Tabela 33 mostra os principais métodos dessa classe (SUN,

2002).

Tabela 33 – principais métodos da Classe KeyAgreement.

Fonte: (SUN, 1999).

public static KeyAgreement getInstance

(String algoritmo);

Cria um objeto KeyAgreement com um

algoritmo de concordância de chaves

específico.

public static KeyAgreement getInstance

(String algoritmo, String provedor);

Cria um objeto KeyAgreement com um

algoritmo de concordância de chaves e o

provedor específico.

public void init(Key chave); Inicializa o objeto KeyAgreement com a

chave privada.

public void init(Key chave, SecureRandom

sr);

Inicializa o objeto KeyAgreement com a

chave privada e uma fonte randômica.

public void init(Key chave,

AlgorithmParameterSpec parametros);

Inicializa o objeto KeyAgreement com a

chave privada e os parâmetros de algoritmo.

public void init(Key chave,

AlgorithmParameterSpec parametros,

SecureRandom sr);

Inicializa o objeto KeyAgreement com a

chave privada, os parâmetros de algoritmo e

uma fonte randômica.

public Key doPhase(Key chave, boolean

ultimafase);

Executa a próxima fase e verifica se é a

última.

public byte[] generateSecret(); Gera uma chave secreta.

public SecretKey generateSecret(String

algoritmo);

Gera uma chave secreta de acordo com o

algoritmo especificado.

77

2.2.5. Classe SealedObject

Essa classe disponibiliza ao programador a possibilidade de criar um objeto e proteger sua

confidencialidade com um algoritmo criptográfico (SUN, 2002).

Conforme (SUN, 2002), qualquer objeto que implemente a interface java.io.serializable,

pode criar um SealedObject que encapsula o objeto original, em formato serializado e sela (cifra)

seu conteúdo serializado, usando um algoritmo criptográfico, como um DES, para proteger a

confidencialidade. O conteúdo depois pode ser decifrado e de-serializado para obter o objeto

original.

As Tabelas 34 e 35, mostram um trecho de código que usa um algoritmo criptográfico

DES e criando um objeto SealedObject e recuperando o objeto original, respectivamente.

Tabela 34 – Código para criar um SealedObject.

Fonte: (SUN, 1999).

Cipher c = Cipher.getInstance("DES");

c.init(Cipher.ENCRYPT_MODE, chavesecreta);

SealedObject so = new SealedObject("Isso é segredo", c);

Tabela 35 – Código para obter o Objeto original novamente.

Fonte: (SUN, 1999).

c.init(Cipher.DECRYPT_MODE, chavesecreta);

try {

String s = (String)so.getObject(c);

} catch (Exception e){

System.out.println(e);}

} ;

78

2.3. TÉCNICAS DE IMPLEMENTAÇÃO E TESTES

2.3.1. MessageDigest com MD5

Para o teste com Message Digest foi usado o algoritmo de MD5 para gerar o hash da

mensagem. A Figura 34 apresenta o código fonte MDTeste, que gera o hash de uma String e

imprime a mensagem original e o código hash na tela. Um hash tem sempre um tamanho fixo, esse

tamanho varia de acordo com o algoritmo usado para gerar o código hash.

Figura 34 – Aplicação MDTeste.

O hash gerado da string “Trabalho de conclusao de Curso II ” s erá sempre o mesmo, mas

caso seja alterado um caractere, o hash será totalmente diferente, o que prova que o texto foi

alterado. A Figura 35 mostra o hash de três mensagens, o primeiro é gerado, em seguida a

mensagem original é alterada , como mostra o retângulo na própria Figura 35, e gera um hash

diferente. A terceira mensagem é igual a primeira e gera o mesmo hash, confirmando que a

mensagem é a mesma.

79

Figura 35 – Hash da Message Digest MDTeste

2.3.2. DESTeste

O teste usando os mecanismos de criptografia do Java, foi feito util izando o algoritmo

DES. Neste teste é necessário que seja adicionado um provedor de serviços criptográficos (foi

usado o provedor fornecido pela Sun), em seguida é gerado uma chave secreta, como mostra o

código fonte da Figura 36. É criado um objeto Cipher e inicilializado, para então poder cifrar o

texto. Para tornar mais claro o teste, será impresso o texto original, após ter sido cifrado, o texto é

novamente impresso. Para finalizar o teste, o texto é decifrado, para isso o Cipher é novamente

inicializado, mas no modo para decifrar, então o texto é decifrado e impresso, mostrando ser igual

ao texto original.

Pode-se observar ainda no código da Figura 36, que o Cipher é criado usando o algoritmo

DES, no modo ECB (Eletronic CodeBook) e o padding é o PKCS5.

80

Figura 36 – Aplicação DESTeste.

A Figura 37 apresenta o resultado do teste, num modelo de criptografia, o texto cifrado

será sempre diferente toda vez que for criada uma chave secreta. Por isso, se o DESTeste for

executado por duas vezes com o mesmo texto, serão gerados textos cifrados totalmente diferentes.

Figura 37 – Resultado do 1º teste com criptografia usando DES.

Na Figura 38, é usado o mesmo código fonte da Figura 36, porém o texto original é

modificado, observa-se que o tamanho da mensagem cifrada também diminui consideravelmente, o

que não acontece no caso da Message Digest.

81

Figura 38 – Resultado do 2º teste com criptografia usando DES.

3. FERRAMENTAS RELACIONADAS

A Sun disponibil iza algumas ferramentas para auxiliar o uso de assinaturas digitais. Essas

ferramentas podem ser usadas para criar chaves, assinar um documento, importar e exportar chaves

e certificados como sendo confiáveis. Para mostrar o uso dessas ferramentas, usando um applet,

será mostrado um guia passo a passo para criar um arquivo JAR, gerar as chaves, assinar o arquivo

JAR, exportar o certificado de chave pública, importar o certificado como certificado confiável e

criar um arquivo de política.

O applet que será usado nesse exemplo, é um applet fornecido pela Sun. Este applet teve

algumas alterações e mesmo assim não é tratado com um código confiável, por isso deve ser

colocado na caixa de areia. Porém a sua função é escrever um arquivo e não deverá ter essa

permissão concedida na caixa de areia.

A Figura 39, mostra o código fonte do writeFile.java (SUN, 2003).

82

Figura 39 – Applet writeFile.

O primeiro passo é criar um arquivo JAR contendo o arquivo .class do applet. A Figura 40

mostra o arquivo WriteFile.jar sendo criado contendo o arquivo writeFile.class dentro dele.

Figura 40 – Criação de um arquivo JAR.

83

O arquivo .jar será posteriormente assinado, mas antes precisa-se ter certeza de que já

possui as chaves para efetuar a assinatura, caso não tenha a chave é necessário criá-las, para isso a

uma ferramenta específica, a ferramente Keytool.

3.1. KEYTOOL

Caso não existam chaves válidas do assinante, é necessário criar as chaves. Para facilitar a

criação das chaves, pode-se usar a ferramenta Keytool. Essa ferramenta possui alguns comandos

específicos, como mostra a Tabela 36.

Tabela 36 – Principais comandos da ferramenta Keytool.

-genkey Gera o par de chaves.

-alias Nome usado para referenciar a entrada no

Keystore.

-keypass Senha para a chave privada.

-keystore Indica o Keystore que será criado ou usado.

-storepass Senha para o Keystore.

-validity Número de dias que o certificado deve ser

válido

-certreq Faz requisição de um certificado de

assinatura

A Figura 41, apresenta a criação de um par de chaves usando a ferramenta keytool e

alguns comandos citados na Tabela 36. observa-se que após util izar o comando keytool, o usuário

será lembrado do seu distinguished-name, onde deverão ser passados os dados pedidos e ao final se

estiver certo dos dados fornecidos, é necessário a confirmação com o comando “yes”.

Ao criar a chave, pode-se armazená-la em uma banco de dados de chaves, keystore, se já

existir um pode-se apenas adicionar uma entrada a ele, ou poderá ser criado um novo keystore,

como nesse caso que foi criado o keystore “projeto” (Figura 41).

84

Figura 41 – Criando as chaves e adicionando um keystore.

Ao gerar as chaves através do “genkey”, um certificado auto-assinado será criado. Caso

seja necessário trocar este certificado por um certificado reconhecido por uma empresa confiável,

deve-se fazer um pedido de assinatura de certificado (CSR CerticateSigning Request), e o resultado

desta solicitação deve ser importado para o keystore. Como na Figura 42.

Figura 42 – Pedido de uma assinatura de certificado CSR.

85

3.2. JARSIGNER

Após ter criado as chaves e ter criado o arquivo JAR. O próximo passo é assinar esse

arquivo JAR. Para isso há uma ferramenta específica para se fazer isso, é a ferramenta Jarsigner.

Que assinará o código usando a chave privada e o alias com entrada no keystore. A Figura 43,

mostra o arquivo JAR sendo assinado.

Figura 43 – Arquivo JAR sendo assinado.

Pode-se observar que são solicitadas a senha do keystore (guilherme) e a senha da chave

privada (gdb123).

O próximo passo, será necessário usar a ferramenta keytool novamente, consiste em

exportar o certificado que está no keystore, com isso, a chave pública poderá ser distribuída aos

usuários do applet. A Figura 44, exibe o certificado sendo exportado.

Figura 44 – Exportando um certificado.

Usa-se ainda a ferramenta keytool para importar um certificado como confiável. A Figura

45, mostra como é feita uma importação. É importe observar que para concluir a importação, será

perguntado se o certificado é confiável ou não, se for tem que ser digitado “ yes” .

86

Figura 45 – Importação de certificado confiável.

Pode-se observar que muitas informações importantes são mostradas ao importar um

certificado tratado como confiável: os dados do proprietário do certificado, a validade do

certificado, os algoritmos utilizados e etc.

3.3. POLICYTOOL

A última ferramenta a ser analisada é o policytool. Esta ferramenta é usada para criar ou

alterar o arquivo de política do Java, podendo ser usada para o controle de acesso também. Para

iniciar o uso dessa ferramenta, basta digitar “policytool” na linha de comando. A Figura 46 mostra

como deve ser feito e a Figura 46 exibe a tela inicial da ferramenta.

Figura 46 – Iniciando o policytool.

87

Figura 47 – Tela inicial do policytool.

Para adicionar um keystore, deve-se clicar em “Edit” e em seguida “Change Keystore”.

Uma janela igual a mostrada na Figura 48 deve aparecer. E deve ser especificado o local onde o

keystore está armazenado e confirma no botão “ok”.

Figura 48 – Especifica o local do keystore.

88

A janela deve se parecer com a da Figura 49, em seguida, selecione o botão “Add Policy

Entry”, para adicionar uma entrada no arquivo de política. Uma janela igual a da Figura 50 deve

aparecer. Se a caixa de texto do codeBase for deixada em branco, então qualquer applet com a

assinatura especificada poderá ser executada.

Figura 49 – local do Keystore já adicionado

89

Figura 50 – Adiciona uma entrada no arquivo de política.

Deve-se clicar no botão “Add Permission”, para adicionar uma permissão ao applet. A

Figura 51 mostra a janela usada para adicionar uma permissão, já preenchida.

Figura 51 – Adiciona permissão

90

Uma janela como a Figura 52 deve ser mostrada, deve-se especificar o alias da chave, que

foi usada para assinar o applet, na caixa de texto SignedBy. Deve-se clicar no botão “Done”. Uma

tela semelhante a Figura 53 deve aparecer.

Figura 52 – permissão adicionada

91

Figura 53 – arquivo de política com uma entrada adicionada

Deve-se então salvar esse arquivo. Neste caso será criado um novo arquivo de política.

Isso deve ser feito clicando em “ File”, em seguida “ Save As” e especificando o local onde deve ser

armazenado o novo arquivo de política, a caixa de texto “Policy File:” deve conter o local e o nome

da política, nesse caso da nova política que foi chamada ‘minhapoli tica’ (Figura 54).

Figura 54 – Criando novo arquivo de política.

92

Porém, para que essa política tenha efeito sobre o sistema, é necessário adicioná-la no

arquivo de segurança do Java, o “java.security” (Figura 55).

Figura 55 – Adicionando uma entrada no arquivo de Segurança do Java.

Para executar o applet, deve-se criar um arquivo HTML contendo o arquivo .class e o

applet assinado (Figura 56).

Figura 56 – Arquivo HTML para executar o applet sWriteFile.jar

Um aviso irá aparecer, para confirmar se realmente pode confiar no applet assinado

(Figura 57).

93

Figura 57 – Aviso de segurança.

Caso queira obter mais detalhes do applet assinado, pode clicar no botão “M ore Details” e

uma janela semelhante a da Figura 58 irá ser mostrada.

Figura 58 – Detalhes do certificado.

Ao executar o applet será mostrada uma mensagem informando que houve sucesso na

execução, como mostra a Figura 59.

94

Figura 59 – Resultado da execução do applet writeFile.java

A Figura 60, mostra um diagrama de classes, com as Classes que foram estudadas neste

trabalho e que fazem parte do Pacote de segurança do Java, java.security.

95

Figura 60 – Diagrama de Classes

IV. CONCLUSÕES E RECOMENDAÇÕES

Conforme pôde ser observado neste trabalho, os mecanismos de segurança do Java

possibili tam que aplicações locais ou remotas sejam executadas num sistema local sem que isso

constitua uma ameaça. Além disso, assegura que informações em trânsito possam ser cifradas

usando os controles criptográficos da própria linguagem.

Para aproveitar os recursos de controle de acesso, é necessário elaborar uma política de

segurança bem detalhada, a fim de permitir o acesso somente do que realmente é confiável. Os

arquivos de política definem as permissões para o acesso aos objetos do sistema.

O trabalho foi limitado ao estudo dos mecanismos de controle de acesso e criptografia.

Decidiu-se fazer um estudo aprofundado do mecanismo de controle de acesso, pois o controle de

acesso forma a base do modelo de segurança do Java, além de possuir uma bibliografia escassa que

explica o uso do controle de acesso.

O JCA é a arquitetura de criptografia da linguagem e o JCE é uma extensão do JCA que

contém classes que são consideradas de propriedade americana e que estão sob restrições de

exportação. O JCA e JCE possibilitam a troca de informações e dados de modo mais seguro.

Ao final de cada capítulo, foram feitos testes, com o intuito não apenas de mostrar a forma

de implementar os mecanismos estudados, mas também, apresentar os passos para conseguir

implementar eficientemente os recursos de segurança da linguagem Java, e os passos para

configurar os arquivos de política fornecidos pelo Java como padrão.

Com isso, conclui-se que esse trabalho contribui tanto para desenvolvedores que podem

usar o texto e os códigos fonte, como um guia para desenvolver programas mais seguros, como

também para administradores de sistemas, especificando a localização dos arquivos de segurança do

Java, e mostrando a sintaxe que deve ser usada para modificar a estratégia de segurança.

Optou-se em adicionar um capítulo sobre ferramentas relacionadas ao tema que foram

encontradas durante o estudo, apresentando também passo a passo como utilizá-las.

97

Para tornar este trabalho mais completo, poderia ser feito um estudo e testes baseando-se

no serviço de autenticação e autorização do Java (JAAS) e a API de serviços de segurança gerais do

Java (GSS-API) que foram integrados ao Java na versão J2SDK 1.4. Também podem ser estudados

e aplicados os avanços adicionados na versão recém lançada do J2SDK 1.5.

Outra recomendação para trabalho futuro que pode ser baseado neste trabalho, seria

desenvolver um pacote com os mecanismos de segurança apresentados, fornecendo uma interface

mais amigável, facili tando o uso das técnicas descritas neste trabalho.

98

BIBLIOGRAFIA

ASSUNÇÃO, Marcos F. A. Guia do Hacker Brasileiro. Visual books. Florianópolis

2002. p. 189

BALFANZ, Dirk., DEAN, Drew., SPREITZER, Mike. A Secur ity Infrastructure for

Distr ibuted Java Applications. In: Proc. of 2000 IEEE Symposium on Security and Privacy, May,

2000.

BROSE, Gerald., KOCH, Manuel., LÖHR, Klaus-Peter. I ntegrating Access Control

Design into the Software Development Process. In: Proceedings of the Integrated Design and

Process Technology, June 2002.

DEITEL, H. M., DEITEL, P. J., Java como programar , ed. Bookman, 4 edição, Prentice

Hall, 2002. p. 1386.

FERREIRA, Aurélio Buarque de Holanda. Dicionár io Aurélio Básico da L íngua

Por tuguesa. 3. ed. Rio de Janeiro: Nova Fronteira. 1988. p. 627.

GOIS, Matheus C. de A., BEZERRA, H. M. de A., BARROS, P. G., SANTOS, A.,

Revista Eletrônica de Iniciação Científica, Tecnologias Java para Segurança de Sistemas,

Publicação da SBC, Ano I II , Volume I I I , Número IV, Dezembro de 2003, ISSN 1519-8219.

(http://www.sbc.org.br/reic/edicoes/2003e4/)

ISO/IEC. 15408-1:1999(E) - Par t 1: Introduction and general model. In: Information

Technology – Secur ity Techniques - Evatuation Criteria for IT Security, First edition, ISO/IEC,

December 1999.

LAMPSON, Butler W. Protection In: 5th Princeton Symposium on Information Sciences

and Systems, March 1971. Reprinted in ACM Operating Systems Review, v. 8, n. 1, p. 18-24, 1974.

99

LANDWEHR, C. Computer Secur ity, International Journal of Information Security, v. 1,

n. 1, pp. 2-13, ISSN 1615-5262, Springer-Verlag, 2001.

LOUSANO, José W., Ávila, Renato N. P., Zanini, Dalton C., Segurança de dados em

Computação. (http://proenca.uel.br/curso-redes-especializacao/2000-uel/trab-02/equipe-03), visto

em setembro de 2003.

MCGRAW, Gary., FELTEN, Edward W.. Java Secur ity : Hostile Applets, Holes and

Antidotes. John Wiley and Sons, 1997.

OBELHEIRO, Rafael R., Modelos de segurança baseados em Papéis para sistemas de

larga escala: a proposta RBAC-JaCoWeb. Dissertação de Mestrado. Florianópolis, 2001

OAKS, Scott. Segurança de dados em Java, Editora Ciência Moderna Ltda, Rio de

Janeiro. 1999. p. 433.

SUN, Microsystems Inc. The Java Language Specification. Sun Microsystems Inc.,

Mountain View, CA, October 1995.

SUN, Microsystems Inc. Java Secur ity Architecture (JDK 1.2). Sun Microsystems Inc.,

Mountain View, CA, October 1998.

SUN, Microsystems Inc. Java Cryptography Architecture API Specification &

Reference. Sun Microsystems Inc., Mountain View, CA, December 1999.

SUN, Microsystems Inc. Trail: Secur ity in Java 2 SDK 1.2: Table of Contents. Sun

Microsystems Inc., Mountain View, CA, December 1999.

(http://java.sun.com/docs/books/tutorial/security1.2/TOC.html)

SUN, Microsystems Inc. Java Authentication and Author ization Service (JAAS)

Reference Guide. Sun Microsystems Inc., Mountain View, CA, 2001

(http://java.sun.com/j2se/1.4.1/docs/guide/security/jaas/JAASRefGuide.html).

100

SUN, Microsystems Inc. JAAS – Java Authentication and Author ization Service

Tutor ial. Sun Microsystems Inc. Mountain View, CA, 2002.

(http://java.sun.com/j2se/1.4.1/docs/guide/security/jaas/tutorials/index.html)

SUN, Microsystems Inc. Java Cryptography Extension (JCE), Reference Guide. Sun

Microsystems Inc., Mountain View, CA, January 2002.

(http://java.sun.com/j2se/1.4.2/docs/guide/security/jce/JCERefGuide.html)

SUN, Microsystems Inc. Java Secur ity Architecture (JDK 1.4.2). Sun Microsystems

Inc., Mountain View, CA, March 2002.

(http://java.sun.com/j2se/1.4.2/docs/guide/security/spec/security-specTOC.fm.html)

SUN, Microsystems Inc. Glossary. Sun Microsystems Inc., Mountain View, CA, 2003

(http://java.sun.com/docs/books/tutorial/security1.2/summary/glossary.html#DigitalSignature)