Universidade Federal de Santa Catarina Departamento de Automaç

Transcrição

Universidade Federal de Santa Catarina Departamento de Automaç
Universidade Federal de Santa Catarina
Departamento de Automação e Sistemas
Grupo de Estudos de Agentes Móveis e Segurança
RELATÓRIO TÉCNICO
Implementação das Classes PRRepository e PathRegister do pacote
AgentSec
Rafael José Deitos
Florianopólis, abril de 2004.
1
Figura 1: Notação do esquema Repositório Seguro de Resultados Parciais
1
Introdução
No esquema de proteção de agentes móveis e das plataformas com
as quais estes interagem, visando assegurar a integridade daqueles, o
esquema proposto por Wangham em [1] suporta uma terceira técnica
para resultados parciais recolhidos durante as viagens do agente:
Repositório Seguro de Resultados Parciais.
Além do repositório de resultados parciais, o esquema conta com
uma outra técnica que consiste em um registrador de caminhos. O
objetivo deste é o de prover proteção para a plataforma e proteção
para os agentes móveis pois detecta as possı́veis violações da integridade do código e do estado do agente e ajuda ainda no processo
de identificação de plataformas maliciosas.
Através da implementação do Registrador de Caminhos, num
âmbito mais geral, será implementado um Controle Social da Reputação das Plataformas.
2
2.1
Classe PRRepository
Descrição
Para agentes one-hop, a técnica de assinatura de código e de dados somente leitura garante a integridade dos agentes, porém, para
agentes multi-hop esta técnica não é suficiente. Assim, os dados
sensı́veis, gerados em uma plataforma, devem ser armazenados em
um repositório seguro de dados parciais, chamado de PRRepository,
que será carregado pelo agente, para que possı́veis modificações de
plataformas maliciosas possam ser detectadas.
Uma das caracterı́sticas do repositório de resultados parciais é a
possibilidade de inserção de resultados. Os protocolos criptográficos
usados pelas plataformas para inserir e proteger um resultado no
PRRepository são semelhantes ao protocos P1 e P2, definidos por
Karjoth et al.(1998), da Famı́lia KAG definidos em [1].
2
Para a descrição do procedimentos necessários para a inicialização do repositorio, para inserção de um resultado parcial e para
verificação da integridade do repositorioRP, é utilizada a seguinte
notação (ver tabela 1).
2.2
Pseudo-código
class PRRepository implements Serializable {
private String _protocol;
ArrayList _PRList;
private int _n = -1;
private SDSIRSAPublicKey _pub0;
private SDSIRSAPublicKey _nextPub;
public PRRepository(
String,
Credentials,
SDSIRSAPublicKey,
SDSIRSAPrivateKey,
SDSIRSAPublicKey) {
}
public boolean addParcialResult(
Object,
byte[],
SDSIRSAPublicKey,
SDSIRSAPrivateKey,
SDSIRSAPublicKey) throws IOException {
}
public String getProtocol() {
}
public VerificationResult verify(
SDSIRSAPublicKey,
RORepository) {
}
3
Figura 2: Inicialização do Repositório de Resultados Parciais
public VerificationResult verify(
SDSIRSAPublicKey,
SDSIRSAPrivateKey,
RORepository) throws IOException {
}
Cada objeto PRRepository conterá os seguintes atributos:
protocol : String que define o protocolo criptográfico que será
usado pelo repositório;
PRList : ArrayList onde ficarão armazenados os resultados parciais adicionados pelas plataformas;
n : quantidade de elementos da lista de resultados parciais;
pub0 : chave pública da plataforma inicial (P0);
nextPub : chave pública da próxima plataforma a ser visitada
pelo agente que carrega o repositório de resultados parciais;
Além destes atributos cada objeto da classe PRRepository possui
alguns métodos, sendo eles:
constructor() : inicializa um novo repositório de resultados parciais criando o objeto que conterá os resultados a serem adicionados. Depois, seta a chave pública que será a chave P0 e a chave
pública da próxima plataforma a ser visitada. Então o proprietário do agente (plataforma de origem P0) gera um número
aleatório r0 e computa o valor de ho, aplicando um função hash
one-way sobre ro e a identidade da primeira plataforma a ser
visitada (P1) (passo 1 da Figura 2). Este h0 é o valor âncora
da relação de encadeamento dos resultados parciais recolhidos. O proprietário deve ainda cifrar o valor ro com a sua
4
Figura 3: Protocolos para a inserção de resultados parciais
própria chave pública. Em seguida, o resultado deste processo
de cifragem mais o identificador único do agente e a relação
de encadeamento h0 são assinados pelo proprietário do agente,
criando o resultado parcial protegido RP0 (passo 2, Figura 2).
No esquema proposto, o identificador único do agente é o valor
resultante da aplicação da função hash sobre o objeto Credencials. Finalmente, no passo 3, o resultado parcial é inserido no
repositorioRP (RPo) e enviado para a plataforma P1.
addParcialResult() : adiciona um resultado parcial de acordo
com o protocolo definido na criação do repositório. A adição
de um novo resultado parcial obedece a ordem etabelecida na
figura 3 para cada protocolo. Os parâmetros exigidos para a
adição de um novo repositório são: um Object, um byte[], uma
chave pública SDSIRSAPublicKey - que será a pub0 e um par
de chaves SPKI/SDSI - RSA;
getProtocol() : retorna o protocolo utilizado pelo repositório;
verify() : verifica a integridade do repositório para os protocolos
A ou B com os seguintes parâmetros: uma chave pública SDSIRSAPublicKey e um objeto da classe RORepository;
verify() : verifica a integridade do repositório para o protocolo
C. Somente pode ser feita pela plataforma inicial. Para tal
os parâmetros necessários são: uma chave pública SDSIRSAPublicKey - chave da plataforma atual - , uma chave privada
SDSIRSAPrivateKey - par correspondente à chave pública utilizada na inicialização - , e um objeto da classe RORepository;
5
2.3
Código Fonte
O código fonte completo da classe PRRepository, bem como de suas
classe internas, está disposto na seção Apêndice deste documento.
2.4
Testando a Funcionalidade do Repositório - A Classe
PRRepAgentTest
Na perspectiva de testar a funcionalidade do PRRepository foi implementado um agente móvel multi-saltos que percorre plataformas
pré-definidas carregando um repositório de resultados parciais. A
cada salto ele introduz novos resultados e verifica a integridade dos
existentes.
O agente teste - PRRepAgentTest - foi implementado de modo
a prover todas as funções estruturadas no repositório de resultados
parciais. No entanto, como descrito por Michelle S. Wangham ,
para a criação e utilização do repositorio de resultados parciais se
faz necessária a criação de um repositório de dados somente-leitura.
Desta forma, implicitamente, o agente móvel implementado para os
testes do PRRepository contém algumas caracterı́sticas do agente
implementado para os testes do RORepository.
2.4.1
O processo de criação
O agente móvel multi-saltos implementado para os testes de funcionalidade, realizará durante a execução do método onCreation a
criação dos repositórios especificados.
O processo de criação do agente pode, então, ser assim resumidamente descrito: primeiro é feito todo o processo de criação de
um objeto da classe RORepository, que contém as credenciais do
agente sob forma de um objeto da classe Credentials e ainda, a
qualidade de proteção exigida para seu agente proprietário (QoP );
em seguida é feito o hash criptográfico do objeto Credentials contigo no repositório somente-leitura. No passo seguinte, são criados
os dois vetores de dados que conterão os destinos do agente teste e os
identificadores de cada plataforma a percorrer. Feito isto, o agente
está pronto para a criação do repositório de resultados parciais. Por
fim, o agente dispara o método que inicia seu processo de viagem
por diferentes plataformas.
2.4.2
Salto(s) para outra(s) plataforma(s)
Depois de inicializado o processo de serialização, o agente salta até
a próxima plataforma de seu itinerário, que deve estar previamente
6
Figura 4: Esquema de saltos do agente PRAgentTest
inicializada em outra máquina. O esquema de saltos do agente teste
pode ser visualizado na figura 4.
A cada salto, o agente deverá ser interceptado por outro agente,
o SecurityInterceptor, que procederá com as verificações de cada um
dos repositórios carregados pelo agente.
Segue-se, então, um troca de mensagens entre os dois agentes, a
qual pode ser descrita, de seguinte maneira: depois que a chegada do
DDAgletTest é sinalizada pela classe AgletContextImpl, o agente SecurityInterceptor envia uma mensagem requisitando os repositórios
que estão presentes no agente PRAgletTest. Este, por sua vez, envia
os repositórios que possui, ou seja, os objetos correspondentes ao
RORepository e ao PRRepository. Feito isto, a integridade de cada
repositório é testada separadamente.
2.4.3
O resultado da verificação
Para finalizar, se algum indı́cio de ação maliciosa for encontrado,
o agente teste é removido pelo agente interceptador. Este, por sua
vez, guarda um objeto, resultado da verificação, que contém as listas
de plataformas suspeitas e confiáveis.
Por outro lado, se os testes de integridade dos repostitórios não
apresentarem nenhum indı́cio de ação maliciosa, o agente teste fica
livre para prosseguir sua viagem para outras plataformas.
Como parte integrante de um sistema maior, o agente teste utilizado, PRAgletTest, pode ser utilizado como modelo para qualquer
agente móvel multi-saltos no qual deseja-se garantir a integridade
das informações por ele transportadas.
7
PRRepository - Classes Internas
3
Para que se pudesse encapsular as informações sobre uma determinada classe de objetos, visando otimizar o processo de serialização e desserialização, utilizou-se da criação de classes internas
ao repositório de resultados parciais.
3.1
3.1.1
PRRepository.CipheredObject
Descrição
Classe utilizada para encapsular informações resultantes do processo
de cifragem dos dados direcionados.
3.1.2
Pseudo-Código
class CipheredObject implements Serializable {
byte[][] _chipered;
CipheredObject(byte[][]) {
}
public final byte[][] getChiphered() {
}
}
Cada objeto desta classe possui os seguinte atributos e métodos:
ciphered : objeto que contém os dados direcionados cifrados;
constructor(byte[ [])]: cria um novo objeto CipheredObject armazenando na variável de classe ciphered os dados direcionados
cifrados;
getCiphered() : retorna o objeto que contém os dados direcionados cifrados.
3.1.3
Código Fonte
O código fonte completo está disposto na seção Apêndice deste documento.
8
3.2
3.2.1
PRRepository.CredsHash
Descrição
Classe utilizada para encapsular um byte[] que é o resultado da
aplicação da função sdsi.Hash sobre um objeto da classe Credentials.
3.2.2
Pseudo-Código
class CredsHash implements Serializable {
byte[] _credsHash;
CredsHash(byte[]) {
}
public final byte[] getHash() {
}
}
Cada objeto desta classe possui os seguinte atributos e métodos:
chipered : contém o sdsi.Hash do objeto Credentials do agente;
constructor(byte[]) : cria um novo objeto da classe CredsHash
armazenando na variável de classe ciphered o sdsi.Hash do objeto Credentials;
getHash() : retorna o byte[] usado na inicialização, que contém o
sdsi.Hash;
3.2.3
Código Fonte
O código fonte completo da classe está disposto na seção Apêndice
deste documento.
3.3
3.3.1
PRRepository.ParcialResult
Descrição
Classe utilizada para guardar resultados parciais que fazem parte
do PRRepository.
3.3.2
Pseudo-Código
class ParcialResult implements Serializable {
9
Object _pri;
ParcialResult(Object) {
}
public Object getParcial() {
}
}
Cada objeto desta classe possui os seguinte atributos e métodos:
pri : corresponde a um resultado parcial qualquer;
constructor(Object) : instancia um novo objeto da classe ParcialResult armazenando em pri o resultado parcial;
getParcial() : retorna o objeto que corresponde ao resultado parcial.
3.3.3
Código Fonte
O código fonte completo da classe está disposto na seção Apêndice
deste documento.
3.4
3.4.1
PRRepository.VerificationResult
Descrição
A classe VerificationResult foi implementada com o objetivo de
guardar o resultado de uma verificação de integridade do repositório
de resultados parciais.
3.4.2
Pseudo-Código
class VerificationResult implements Serializable {
private Object[] _reliablePR;
private Object[] _suspectPR;
boolean _ret = false;
VerificationResult(int) {
}
VerificationResult(boolean) {
}
10
public Object[] getReliablePlats() {
}
public Object[] getSuspectPlats() {
}
public boolean getResult() {
}
}
Cada objeto desta classe possui os seguinte atributos e métodos:
reliablePR : atributo que armazena os identificadores (chaves
públicas) das plataformas consideradas confiáveis;
suspectPR : atributo que armazena os identificadores (chaves
públicas) das plataformas consideradas suspeitas;
ret : atributo que representa o resultado da verificação corrente;
constructor(int) : inicializa um novo objeto VerificationResult
criando os conjuntos de plataformas confiáveis e suspeitas, se
houver. Armazena nos atributos de classe esses conjuntos de
pataformas;
int i : inteiro correspondendo a posição do resultado parcial suspeito dentro da lista de resultados parciais: PRList.
getReliablePlats() : retorna o conjunto de plataformas confiáveis;
getSuspectPlats() : retorna o conjunto de plataformas suspeitas;
getResult() : retorna o resultado da verificação. É um dado tipo
boolean: true se o último elemento de PRList estiver ı́ntegro,
o que significa que todos os outros anteriores estarão.
3.4.3
Código Fonte
O código fonte completo da classe está disposto na seção Apêndice
deste documento.
11
4
4.1
Classe PathRegister
Descrição
O esquema proposto por Michelle S. Wangham conta com uma
técnica que consiste em um registrador de caminhos. O objetivo
deste é o de prover proteção para a plataforma e proteção para os
agentes móveis pois detecta as possı́veis violações da integridade do
código e do estado do agente e ajuda ainda no processo de identificação de plataformas maliciosas.
A implementação desta técnica se fez possı́vel através da classe
PathRegister do pacote br.ufsc.das.agentSec, que é um registrador
de caminhos onde ficam registradas todas as plataformas por onde
o agente percorre durante sua viagem. Esses caminhos registrados
são, na verdade, resultados parciais adicionados a um repositório de
resultados parciais contido no registrador de caminhos.
A classe PathRegister permite, ainda, a definição de quando os
testes de integridade devem ser executados, isto é, os testes podem
ser feitos em cada plataforma ou somente na plataforma de origem.
Através da implementação do Registrador de Caminhos, num
âmbito mais geral, será implementado um Controle Social da Reputação das Plataformas.
4.2
Pseudo-Código
class PathRegister implements Serializable {
private PRRepository _paths;
public PathRegister(Credentials creds, SDSIRSAPublicKey PnextPub,
SDSIRSAPublicKey pub, SDSIRSAPrivateKey priv) {
}
public void addPath(byte[] credsHash, SDSIRSAPublicKey PnextPub,
SDSIRSAPublicKey pub, SDSIRSAPrivateKey priv) {
}
public SDSIRSAPublicKey getElementAt(int i){
}
public PRRepository getPath(){
}
12
public boolean verifyIntegrity(SDSIRSAPublicKey pub,
RORepository rorep) {
}
}
Cada objeto da classe PathRegister possui os seguintes atributos
e métodos:
paths : atributo que representa o objeto da classe PRRepository
criado para armazenar os caminhos percorridos pelo agente;
constructor(Credentials, PublicKey1 , PublicKey2 , PrivateKey3 )
: faz a inicialização do registrador de caminhos criando um
novo objeto da classe PRRepository, que possibilita a ligação
segura entre cada registro (“caminho percorrido”) e ainda, a
verificação de cada um destes registros. Assim, um registrador
de caminhos nada mais é do que um conjunto de resultados
parciais formando um repositório;
addPath(byte[], PublicKey4 , PublicKey5 , PrivateKey6 ) : a
adição de uma nova entrada ao registrador é feita com a ajuda
do método addParcialResult do repositório de resultados parciais;
getElementAt(int) : recupera o identificador da plataforma a
partir de um ı́ndice fornecido;
getPath() : retorna o objeto que contém o registro de todos os
caminhos percorridos pelo agente;
verifyIntegrity(SDSIRSAPublicKey, RORepository) : checa
a integridade de cada um dos caminhos percorridos pelo agente,
verificando a ligação entre eles, através do método verify do
repositório de resultados parciais;
4.3
Código Fonte
O código fonte completo da classe PathRegister está descrito na
seção Apêndice deste documento.
1 As
chaves usadas são chaves SDSIRSA
13
Figura 5: Esquema de saltos do agente PathRegAgentTest
4.4
Testando a Funcionalidade do Registrador de Caminhos - A Classe PathRegAgentTest
A implementação da classe PathRegister evolveu também a criaçao
de um agente de testes. Este agente, o PathRegAgentTest, é um
agente multi-saltos que percorre plataformas pré-determinadas adicionando novas entradas no registrador de caminhos e ao mesmo
tempo fazendo verificações de integridade.
Para tanto, o agente utilizado nos testes, possui o método onCreation, onde é criado um objeto da classe PathRegister.
4.4.1
O processo de criação
Durante o método onCreation o agente teste inicializa um novo objeto da classe RORepository, que será posteriormente utilizado para
a criação do registrador de caminhos. O repositório somente-leitura
contém a qualidade de segurança exigida pelo agente, que neste caso
é a verificação da integridade do próprio repositório e do registrador
de caminhos.
Depois de criado o repositório somente-leitura, o agente teste
inicializa o registrador de caminhos instanciando um novo objeto da
classe PathRegister.
4.4.2
Salto(s) para outra(s) plataforma(s)
No passo seguinte, o agente teste inicia o processo de saltos para
outras plataformas de acordo com o esquema descrito na figura 5.
Em cada uma das plataformas que o agente teste passa é realizado o teste de integridade do registrador de caminhos e, se nenhum
14
indı́cio de ação maliciosa for encontrado, um novo registro será adicionado.
Para que seja feita a verificação e inserção de novos registros, o
agente teste troca um série de mensagens com o agente interceptador
(SecurityInterceptor ) da plataforma. O procedimento de verificação,
bem como o processo de inserção de novos registros, é o mesmo
utilizado para o repositório de resultados parciais.
4.4.3
O resultado da verificação
A continuidade da viagem do agente teste está intimamente ligada
ao resultado do processo de verificação. Assim, caso seja encontrado algum indı́cio de ação maliciosa em qualquer um dos registros
armazenados, o agente teste é suspenso eplo agente interceptador.
Por outro lado, se nenhum indı́cio de ação maliciosa for encontrado, o agente teste pode prosseguir sua viagem saltando para a
próxima plataforma do seu itinerário.
Como aspecto geral de implementação, o agente que carrega os
repositórios, PathRegAgletTest, pode ser utilizado como modelo para
qualquer agente móvel multi-saltos no qual deseja-se realizar um
registro dos caminhos percorridos garantindo-se a integridade dos
dados armazenados.
5
Considerações Finais
Os resultados obtidos permitem afirmar com segurança que todo o
processo de criação, cifragem, assinatura e posterior verificação de
resultados parciais, que compôem o repositório PRRepository, pode
ser realizado utilizando a classe descrita acima, ficando garantidas
todas as propriedades de segurança requeridas pelo projeto.
6
Apêndice
15
/*
* Created on 19/02/2004
*
Copyright (C) 2004
This program is
modify it under
as published by
of the License,
c Deitos
Rafael Jos~
A
free software; you can redistribute it and/or
the terms of the GNU General Public License
the Free Software Foundation; either version 2
or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package br.ufsc.das.agentSec;
import
import
import
import
import
import
import
import
java.io.IOException;
java.io.Serializable;
java.security.InvalidKeyException;
java.security.NoSuchAlgorithmException;
java.security.SignatureException;
java.util.ArrayList;
java.util.Arrays;
java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import
import
import
import
import
import
prototype.SdsiResolver;
sdsi.SDSIPublicKey;
sdsi.SDSIRSAPrivateKey;
sdsi.SDSIRSAPublicKey;
sdsi.SDSISignature;
sdsi.sexp.SexpParseException;
/**
* Class that implements the Secure Parcial Results Repository of the aglet
16
* intending to protect itself from malicious plataforms maintaining its
* integrity.
*
c Deitos
* @author Rafael Jos~
A
*/
public class PRRepository implements Serializable {
//string que define o protocolo a ser usado
private String _protocol;
//vetor encadeado que contem
//em cada posicao outro vetor com
//a assinatura e os resultados parciais(plainText)
ArrayList _PRList;
//quantidade de elementos no vetor _PRList
//comeca com -1 devido a plataforma 0
private int _n = -1;
//chave publica da plataforma inicial
private SDSIRSAPublicKey _pub0;
//chave publica da proxima plataforma
private SDSIRSAPublicKey _nextPub;
/**
* Creates a new instance of PRRepository
*
* @param prot *
String that means the protocol to be used
* @param creds *
Credentials object of the agent
* @param P1 *
SDSIRSAPublicKey of the next plataform
* @param priv *
SDSIRSAPrivateKey for the signature process
* @param pub *
SDSIRSAPublicKey for the signature process
*/
public PRRepository(String prot, Credentials creds, SDSIRSAPublicKey P1,
SDSIRSAPrivateKey priv, SDSIRSAPublicKey pub) {
//inicializando objeto Helper
Helper _helper = new Helper();
17
//inicializamos o vetor de resultados parciais
_PRList = new ArrayList();
//faz-se _pub0=pub
_pub0 = pub;
//seta chave da proxima plataforma
_nextPub = P1;
//seta o protocolo a ser usado
_protocol = prot;
try {
//gera numero aleatorio -> r0
Random r = new Random();
double r0 = r.nextDouble();
byte[] r0Byte = _helper.double2byteArray(r0);
//transfoma chave publica em um byte[]
byte[] P1byte = _helper.object2byteArray((Object) P1);
//concatena r0 com identificador da plataforma (P1)
byte[] concat = _helper.concatenate(r0Byte, P1byte);
//calcula relacao de encadeamento -> faz o sdsi.Hash deste byte[]
byte[] h0 = _helper.makeHash(concat);
//cifra r0 (como um byte[]) com sua chave publica e guarda em
// CipheredObject
CipheredObject co = new CipheredObject(_helper.cipher(_helper
.double2byteArray(r0), _pub0));
//calcula indentificador unico e guarda no objeto Credshash
CredsHash ch = new CredsHash(_helper.makeHash(_helper
.object2byteArray((Object) creds)));
//objeto ObjectWriter que concatena os elementos calculados
ObjectWriter ow = new ObjectWriter();
ow.writeBytes(h0);
ow.writeObject(co);
ow.writeObject(ch);
// assina usando chaves SDSI
SDSISignature sig = new SDSISignature(ow.getBytes(), priv, pub);
//ARMAZENA O PRIMEIRO ELEMENTO NO VETOR _PRList
bject[] PR0 = new Object[2];
PR0[0] = sig;
PR0[1] = ow.getBytes();
//aqui exatamente armazena vetor
_PRList.add(PR0);
//incrementa contador de elementos
_n++;
} catch (Exception e) {
e.printStackTrace();
18
}
}
/**
* Method that adds new parcial results in the PRRepository
*
* @param pri *
parcial result to be inserted on the _PRList
* @param credsHash *
hash of the Credentials Object
* @param PnextPub *
SDSIRSAPublicKey of the next plataform to be visited
* @param priv *
SDSIRSAPrivateKey for the signing process
* @param pub *
SDSIRSAPublicKey for the signing process
*/
public boolean addParcialResult(Object pri, byte[] credsHash,
SDSIRSAPublicKey PnextPub, SDSIRSAPrivateKey priv,
SDSIRSAPublicKey pub) throws IOException {
//verificacao da autenticidade da plataforma como
//proxima plataforma
boolean isNextPlat = verifyCurrentKey(pub);
if (isNextPlat) {
//ADICIONA RESULTADO PARCIAL
//cria um helper
Helper helper = new Helper();
//RELACAO DE ENCADEAMENTO
//gera numero aleatorio ri
Random r = new Random();
double ri = r.nextDouble();
//byte[] riByte = _helper.double2byteArray(ri);
//transfoma chave publica em um byte[]
byte[] PnextPubByte = helper.object2byteArray((Object) PnextPub);
byte[] concat;
if (_protocol.equalsIgnoreCase("C")) {
//concatena resultado parcial anterior com chave publica
concat = helper.concatenate(helper
.object2byteArray((Object) _PRList.get(_n)),
PnextPubByte);
} else {
//concatena assinatura do resultado parcial anterior com chave
19
// publica
concat = helper.concatenate(
helper.object2byteArray((Object) ((Object[]) _PRList
.get(_n))[0]), PnextPubByte);
}
//calcula relacao de encadeamento -> hash
byte[] hi = helper.makeHash(concat);
//cria objeto ParcialResult
ParcialResult pr = new ParcialResult(pri);
//cria objeto CredsHash
CredsHash ch = new CredsHash(credsHash);
//VERIFICA QUAL PROTOCOLO DEVERA SER USADO
if (_protocol.equalsIgnoreCase("A")) {
//cria resultado parcial protegido
ObjectWriter owA1 = new ObjectWriter();
owA1.writeObject(pr);
owA1.writeDouble(ri);
//cifra com a chave da plataforma inicial "_pub0"
//criando objeto CipheredObject para separar elementos
CipheredObject coA = new CipheredObject(helper.cipher(owA1
.getBytes(), _pub0));
//cria objeto que contem todos os elementos concatenados
ObjectWriter owA2 = new ObjectWriter();
owA2.writeBytes(hi);
owA2.writeObject(ch);
owA2.writeObject(coA);
try {
//assina com chaves SDSI
SDSISignature sig = new SDSISignature(owA2.getBytes(),
priv, pub);
//INSERE O NOVO ELEMENTO EM _PRList
Object[] PRi = new Object[2];
PRi[0] = sig;
PRi[1] = owA2.getBytes();
//aqui exatamente armazena
_PRList.add(PRi);
//incrementa contador de elementos
_n++;
} catch (Exception e) {
_n++;
e.printStackTrace();
}
} else if (_protocol.equalsIgnoreCase("B")) {
20
//cria resultado parcial protegido
ObjectWriter owB = new ObjectWriter();
owB.writeBytes(hi);
owB.writeObject(ch);
owB.writeObject(pr);
owB.writeDouble(ri);
try {
//assina com chaves SDSI
SDSISignature sig = new SDSISignature(owB.getBytes(), priv,
pub);
//INSERE O NOVO ELEMENTO NO VETOR _PRList
Object[] PRi = new Object[2];
PRi[0] = sig;
PRi[1] = owB.getBytes();
//aqui exatamente armazena vetor
_PRList.add(PRi);
//incrementa contador de elementos
_n++;
} catch (Exception e) {
_n++;
e.printStackTrace();
}
} else if (_protocol.equalsIgnoreCase("C")) {
try {
//concatena credsHash, pr e ri
ObjectWriter owC = new ObjectWriter();
owC.writeObject(ch);
owC.writeObject(pr);
owC.writeDouble(ri);
//assina com chaves SDSI
SDSISignature sig = new SDSISignature(owC.getBytes(), priv,
pub);
//criamos um objeto writer para guardar a assinatura
ObjectWriter writSig = new ObjectWriter();
writSig.writeObject(sig);
writSig.writeObject(owC.getBytes());
//cifra a assinatura com chave da plataforma inicial
// "_pub0"
CipheredObject coC = new CipheredObject(helper.cipher(
writSig.getBytes(), _pub0));
//monta resultado parcial com "hi" na PRIMEIRA POSICAO
ObjectWriter owC1 = new ObjectWriter();
owC1.writeBytes(hi);
21
owC1.writeObject(coC);
//INSERE O NOVO ELEMENTO NO VETOR _PRList
_PRList.add(owC1.getBytes());
//incrementa contador de elementos
_n++;
} catch (Exception e) {
_n++;
e.printStackTrace();
}
}
//retorna true = elemento adicionado
return true;
} else {
//plataforma naum autorizada a adicionar
//resultado parcial
return false;
}
}
/**
* Class that stores an object that had been ciphered
*
c Deitos
* @author Rafael Jos~
A
*/
public class CipheredObject implements Serializable {
byte[][] chipered;
/**
* Creates a new instance of CipheredObject
*
* @param b
*
the result of a cipher process
*/
CipheredObject(byte[][] b) {
this.chipered = b;
}
/**
* Method that return the original result of the cipher process
*
* @return the ciphered object
*/
public byte[][] getChiphered() {
22
try {
return this.chipered;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
/**
* Class that stores the Hash of a Credentials object
*
c Deitos
* @author Rafael Jos~
A
*/
public class CredsHash implements Serializable {
byte[] credsHash;
/**
* Creates a new instance of CredsHash
*
* @param b
*
the bye[] meaning the hash function of Credentials
*/
CredsHash(byte[] b) {
this.credsHash = b;
}
/**
* Returns credsHash
*
* @return the hash function of Credentials
*/
public byte[] getHash() {
try {
return this.credsHash;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
23
/**
* Method that returns the protocol of the PRRepository
*
* @return _protocol
*/
public String getProtocol() {
try {
return _protocol;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Class that stores the actual parcial result fo the repository
*
c Deitos
* @author Rafael Jos~
A
*/
public class ParcialResult implements Serializable {
Object pri;
/**
* Creates a new instance of ParcilResult
*
* @param o
*/
ParcialResult(Object o) {
this.pri = o;
}
/**
* Returns the parcial result
*
* @return pri
*/
public Object getParcial() {
try {
return this.pri;
} catch (Exception e) {
e.printStackTrace();
}
return null;
24
}
}
/**
* Class that create lists of parcial results: for reliable and suspect
* ones. Implements the result of a verification process.
*
c Deitos
* @author Rafael Jos~
A
*/
public class VerificationResult implements Serializable {
//PR confiaveis -> result=true
private Object[] reliablePR;
//plataformas suspeitas -> result=false
private Object[] suspectPR;
//the return state
boolean ret = false;
/**
* Creates a new instance of VerificationResult
*
* @param i *
int representing the position of the suspect parcial
*
result
*/
VerificationResult(int i) {
try {
ArrayList PRtemp = _PRList;
if (i == 0) {
//PR0 - todos os PRs saum confiaveis
suspectPR = null;
c a propria lista de PRs
//reliablePR ~
A
reliablePR = _PRList.toArray();
} else {
for (int j = 0; j < i; j++) {
//PR confiaveis
reliablePR = new Object[i + 1];
reliablePR[j] = PRtemp.get(j);
//remove os j primeiros elementos do array
//deixando somente os PR comprometidos
temp.remove(j);
}
25
//agora restam em PRtemp somente
//os PRs comprometidos
suspectPR = PRtemp.toArray();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Creates a new instance of VerificationResult
*
* @param b
*
a boolean
*/
VerificationResult(boolean b) {
//para os casos onde sabe-se de antemao o resultado
ret = b;
}
/**
* Return the plataforms considered reliable
*
* @return reliablePlats
*/
public Object[] getReliablePlats() {
try {
return reliablePR;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Return the plataforms considered suspect
*
* @return suspectPlats
*/
public Object[] getSuspectPlats() {
try {
return suspectPR;
} catch (Exception e) {
26
e.printStackTrace();
}
return null;
}
/**
* Return the boolean result of a verification process
*
* @return true if all the parcial results were reliable
*/
public boolean getResult() {
try {
if (suspectPR == null || suspectPR.length == 0) {
return true;
} else {
return ret;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
/**
* Method that verifies the integrity of the PRRepository for protocols A
* and B
*
* @param Pi *
SDSIRSAPublicKey of the current plataform
* @param rorep *
RORepository object
*/
public VerificationResult verify(SDSIRSAPublicKey Pi, RORepository rorep) {
Helper helper = new Helper();
SdsiResolver resolver = new SdsiResolver();
if (_protocol.equalsIgnoreCase("A") || _protocol.equalsIgnoreCase("B")) {
int iteracao = _n;
//REALIZA TESTE DA INTEGRIDADE DA ASSINATURA
if (verify_repository(Pi)) {
//repositorio intacto!!!
if (iteracao == 0) {
//primeira ou segunda plataforma
27
//NAUM PRECISA TESTAR!!!
//plataforma confiavel
VerificationResult result = new VerificationResult(iteracao);
return result;
} else {
//recalcula H(creds) pegando creds de rorep
//H(creds).length: 16 fixo
byte[] chCalc = helper.makeHash(helper
.object2byteArray(rorep.getCredentials()));
//comeca pelos menores PRs (Lazy)
for (int i = 1; i <= iteracao; i++) {
//TESTA RECURSIVAMENTE OS PRs
byte[] PnextPubByte = null;
if (i == iteracao) {
//ultimo PR
//chave pub = chave da plataforma atual
PnextPubByte = helper.object2byteArray((Object) Pi);
} else {
//recupera chave do _PRList
//recupera elemento " i+1 "
Object[] PRii = (Object[]) _PRList.get(i + 1);
//recupera a assinatura do _PRList
SDSISignature sig = (SDSISignature) PRii[0];
//recuperar a chave publica " i+1 "
SDSIRSAPublicKey pii = resolver.getPubFromSig(sig);
//passa a chave para um byte array
PnextPubByte = helper
.object2byteArray((Object) pii);
}
//concatena assinatura do resultado parcial anterior
// com chave publica
//da proxima plataforma(pii)
byte[] concat = helper.concatenate(helper
.object2byteArray((Object) ((Object[]) _PRList
.get(i - 1))[0]), PnextPubByte);
//calcula relacao de encadeamento " i " -> hash
byte[] hiCalc = helper.makeHash(concat);
//RECUPERA CADA PR DA LISTA SEPARANDO
//O CONTEUDO
Object[] PRi = (Object[]) _PRList.get(i);
//recuperamos o segundo elemento que contem os dados
// concatenados
byte[] element = (byte[]) PRi[1];
28
//inicializacao das variaveis
ObjectReader or = null;
byte[] hiGot = null;
byte[] chGot = null;
try {
//consideramos sempre hi como posicao zero do
// byte[]
or = new ObjectReader(element);
//separamos hi do resto do byte[]
hiGot = or.readByte(hiCalc.length);
//separamos credsHash (posicao 1)
CredsHash ch = (CredsHash) or.readObject();
chGot = ch.getHash();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
//TESTES!!!
//compara-se os arrays
if (Arrays.equals(chCalc, chGot)
&& Arrays.equals(hiCalc, hiGot)) {
if (i == iteracao) {
//hash intacto - PR intacto
// testou ate a ultima plataforma
//acabaram os testes com todas os PR = OK
VerificationResult result = new VerificationResult(
0);
return result;
} else {
//hash intacto - PR intacto
//deve continuar testando pois
//naum acabaram os PRs
}
} else {
//hash corrompido ou PR corrompido
VerificationResult result = new VerificationResult(
i);
return result;
}
}
}
} else {
29
//repositorio corrompido!!!
VerificationResult result = new VerificationResult(false);
return result;
} //fim do teste
} else {
//nenhum protocolo escolhido!!!
JFrame frame = new JFrame();
JOptionPane.showMessageDialog(frame,
"You must choose a valid protocol (A, B or C)", "Warning",
JOptionPane.WARNING_MESSAGE);
return null;
}
return null;
}
/**
* Method that verifies the integrity of the PRRepository for C protocol.
*
* @param Pi *
SDSIRSAPublicKey of the current plataform
* @param priv0 *
SDSIRSAPrivateKey of the inicial plataform
* @param rorep *
RORepository object
*/
public VerificationResult verify(SDSIRSAPublicKey Pi,
SDSIRSAPrivateKey priv0, RORepository rorep) throws IOException {
Helper helper = new Helper();
SdsiResolver resolver = new SdsiResolver();
if (_protocol.equalsIgnoreCase("C")) {
//recupera chave publica que assinou PR0
SDSIRSAPublicKey pub0 = null;
try {
Object[] PR0 = (Object[]) _PRList.get(0);
SDSISignature sig0 = (SDSISignature) PR0[0];
pub0 = resolver.getPubFromSig(sig0);
} catch (Exception e) {
e.printStackTrace();
//Erro na recupera~
A§~
A£o da assinatura
return null;
}
//compara com chave da plataforma atual
30
if (pub0 != null && pub0.equals(Pi)) {
//plataforma atual = primeira plataforma
//TESTA RECURSIVAMENTE ATE ENCONTRAR UM
//RESULTADO PARCIAL INTACTO
int iteracao = _n;
if (iteracao == 0) {
//NAUM PRECISA TESTAR
//primeira ou segunda plataforma
//plataforma confiavel
VerificationResult result = new VerificationResult(iteracao);
return result;
} else {
//h de " i "
byte[] hiCalc = null;
byte[] hiGot = null;
//H(creds) obtido de PR
byte[] chGot = null;
//chave da plataforma a ser testada (direfente da HOME)
SDSIRSAPublicKey pi = null;
//h de " i+1 "
byte[] hiiGot = null;
//chave da plataforma i+1
SDSIRSAPublicKey pii = null;
//testa todos os repositorios sem exce ~
A§~
A£o
for (int i = 1; i <= iteracao; i++) {
try {
//recupera elemento i do vetor _PRList
ObjectReader or1 = new ObjectReader(
(byte[]) _PRList.get(i));
//separamos hi do resto do byte[]
//HI como posicao 0 do byte[] for~
A§amos 16 bytes ->
// RSA algoritm
hiGot = or1.readByte(16);
//recupera objeto cifrado que contem a assinatura
CipheredObject co = (CipheredObject) or1
.readObject();
//recupera byte[][] correspondete a cifra com chave
// publica _pub0
byte[][] ciphered = co.getChiphered();
//decifra com a privada priv0 recuperando o objeto
// cifrado
byte[] sigByte = helper.deCipher(ciphered, priv0);
//com um ObjectReader recuperamos a assinatura
31
ObjectReader or2 = new ObjectReader(sigByte);
SDSISignature sigRecovered = (SDSISignature) or2
.readObject();
//recupera os objetos assinados
byte[] signedObjects = (byte[]) or2.readObject();
Objecer or5 = new ObjectReader(signedObjects);
//agora recupera o hash(creds) do byte[] assinado
//corresponde a posicao 1 de signedObjects
CredsHash hCred = (CredsHash) or5.readObject();
chGot = hCred.getHash();
//recupera a CHAVE PUBLICA da plataforma " i "
pi = resolver.getPubFromSig(sigRecovered);
//#########################################
if (i != iteracao) {
//recupera elemento i+1 do vetor _PRList
ObjectReader or3 = new ObjectReader(
(byte[]) _PRList.get(i + 1));
//separamos hi do resto do byte[]
//HI como posicao 0 do byte[] for~
A§amos 16 bytes
// -> RSA algoritm
hiiGot = or3.readByte(16);
//recupera objeto cifrado que contem a
// assinatura
co = (CipheredObject) or3.readObject();
//recupera byte[][] correspondete a cifra com
// chave publica _pub0
ciphered = co.getChiphered();
//decifra com a privada priv0 recuperando o
// objeto cifrado
sigByte = helper.deCipher(ciphered, priv0);
//com um ObjectReader recuperamos a assinatura
ObjectReader or4 = new ObjectReader(sigByte);
sigRecovered = (SDSISignature) or4.readObject();
//recupera a CHAVE PUBLICA da plataforma " i+1
// "
pii = resolver.getPubFromSig(sigRecovered);
//CALCULA hi
//concatena resultado parcial anterior com
// chave publica i+1
byte[] concat = helper.concatenate(helper
.object2byteArray((Object) _PRList
.get(i - 1)), helper
.object2byteArray((Object) pii));
32
//calcula relacao de encadeamento novamente ->
// hash
hiCalc = helper.makeHash(concat);
} else {
//TESTE DO ULTIMO PR
c a propria plataforma HOME
//a proxima ~
A
pii = Pi;
//CALCULA hi
//concatena resultado parcial anterior com
// chave publica da home
byte[] concat = helper.concatenate(helper
.object2byteArray((Object) _PRList
.get(i - 1)), helper
.object2byteArray((Object) pii));
//calcula relacao de encadeamento novamente ->
// hash
hiCalc = helper.makeHash(concat);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//recalcula H(creds) pegando creds de rorep
//H(creds).length: 16 fixo
byte[] chCalc = helper.makeHash(helper
.object2byteArray(rorep.getCredentials()));
//TESTES!!!
//compara-se os arrays
if (Arrays.equals(chCalc, chGot)
&& Arrays.equals(hiCalc, hiGot)) {
if (i == iteracao) {
//hash intacto - PR intacto
// testou ate a ultima plataforma
//acabaram os testes com todas os PR = OK
VerificationResult result = new VerificationResult(
0);
return result;
} else {
//hash intacto - PR intacto
//deve continuar testando pois
//naum acabaram os PRs
33
}
} else {
//hash corrompido ou PR corrompido
VerificationResult result = new VerificationResult(
i);
return result;
}
}
//problemas na verificacao
//retorna falso
VerificationResult result = new VerificationResult(false);
return result;
}
} else {
c HOME
//chaves n~
A£o coincidem-> plataforma naum ~
A
//nenhum teste deve ser feito
VerificationResult result = new VerificationResult(true);
return result;
}
} else {
//nenhum protocolo escolhido!!!
JFrame frame = new JFrame();
JOptionPane.showMessageDialog(frame,
"You must choose a valid protocol (A, B or C)", "Warning",
JOptionPane.WARNING_MESSAGE);
return null;
}
}
/**
* Checks if the current key is equals the next plataform’s key
*
* @param Pi *
SDSIRSAPublicKey of the current plataform
* @return truefalse
*/
private boolean verifyCurrentKey(SDSIRSAPublicKey Pi) {
try {
if (_nextPub.equals(Pi)) {
return true;
}
return false;
} catch (Exception e) {
34
e.printStackTrace();
}
return false;
}
/**
* Method that verifies the integrity of the SDSSIgnature of the last
* parcial result in the array.
*
* @param pub
*
SDSIPublicKey used on the signing process
* @return false when the repository had been corrupted
* @throws SignatureException
*/
private final boolean verify_repository(SDSIPublicKey pub) {
byte[] data = null;
SDSISignature sig = null;
if (_protocol.equalsIgnoreCase("A") || _protocol.equalsIgnoreCase("B")) {
//recuperando os dados => resultado parcial
data = (byte[]) ((Object[]) _PRList.get(_n))[1];
sig = (SDSISignature) ((Object[]) _PRList.get(_n))[0];
}
boolean result;
try {
//pub = chave da plataforma que assinou o PR
result = sig.verify(pub, data);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
} catch (SexpParseException e) {
e.printStackTrace();
}
if (result = true) {
return true;
} else
return false;
}
}
35
/*
* Created on 25/03/2004
*
Copyright (C) 2004
This program is
modify it under
as published by
of the License,
c Deitos
Rafael Jos~
A
free software; you can redistribute it and/or
the terms of the GNU General Public License
the Free Software Foundation; either version 2
or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package br.ufsc.das.agentSec;
import java.io.IOException;
import java.io.Serializable;
import prototype.SdsiResolver;
import sdsi.SDSIRSAPrivateKey;
import sdsi.SDSIRSAPublicKey;
import sdsi.SDSISignature;
/**
* Class that implements a path register intending to create a social control
* the related plataforms
*
* @author Rafael J. Deitos
*/
public class PathRegister implements Serializable {
//registro dos caminhos
private PRRepository _paths;
/**
* Constructor: creates a new instantce of PathRegister
36
*
* @param creds
*
the Credentials object
* @param PnextPub
*
a SDSIRSAPublicKey
* @param pub
*
a SDSIRSAPublicKey
* @param priv
*
a SDSIRSAPrivateKey
*/
public PathRegister(Credentials creds, SDSIRSAPublicKey PnextPub,
SDSIRSAPublicKey pub, SDSIRSAPrivateKey priv) {
try {
//invoca o construtor do PRRepository com protocolo B
_paths = new PRRepository("B", creds, PnextPub, priv, pub);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Add a new path in the path register
*
* @param credsHash
*
a sdsi.Hash of the Credentials object
* @param PnextPub
*
a SDSIRSAPublicKey
* @param pub
*
a SDSIRSAPublicKey
* @param priv
*
a SDSIRSAPrivateKey
*/
public void addPath(byte[] credsHash, SDSIRSAPublicKey PnextPub,
SDSIRSAPublicKey pub, SDSIRSAPrivateKey priv) {
//cria novo resultado parcial a ser adicionado
ObjectWriter ow;
try {
ow = new ObjectWriter();
ow.writeObject(pub);
ow.writeObject(PnextPub);
byte[] pri = ow.getBytes();
//adiciona resultado em _paths
_paths.addParcialResult(pri, credsHash, PnextPub, priv, pub);
37
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns a specified plataform ID
*
* @param i
*
the integer representing the index of the element
* @return the SDSIRSAPublicKey of the plataform
*/
public SDSIRSAPublicKey getElementAt(int i) {
SdsiResolver resolver = new SdsiResolver();
SDSIRSAPublicKey pub = null;
try {
c sempre do tipo B
//admitimos que PR ~
A
//obtem o vetor correspondente ao primeiro elemento de PRList
Object[] firstPR = (Object[]) _paths._PRList.get(i);
//obtem a assinatura (primeiro elemento) deste elemento
SDSISignature sig = (SDSISignature) firstPR[0];
//obtem a chave publica que gerou esta assinatura
pub = resolver.getPubFromSig(sig);
} catch (Exception e) {
e.printStackTrace();
}
return pub;
}
/**
* Returns the PRRepository contained in the path register
*
* @return the PRRepository object
*/
public PRRepository getPath() {
try {
return _paths;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
38
/**
* Verify the integrity of the Path Register object
*
* @param pub
*
a SDSIRSAPublicKey
* @param rorep
*
a RORepository
* @return true or false
*/
public boolean verifyIntegrity(SDSIRSAPublicKey pub, RORepository rorep) {
try {
//invocamos o metodo verify do PRRep com chave publica
PRRepository.VerificationResult result = _paths.verify(pub, rorep);
boolean verify = result.getResult();
return very;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
39
Referências
[1] M. WANGHAM, Um Esquema de Segurança de Agentes Móveis,
PhD thesis, Universidade de Santa Catarina, 2004.
40

Documentos relacionados