sábado, 9 de junho de 2007

Reflections on Trusting Trust: Uma Visão baseada em Software Livre

[THOMPSON, 1995] em sua publicação clássica apresenta uma constatação bastante incômoda. Ele trata da confiabilidade de códigos não produzidos localmente ou que não exista a possibilidade de verificação de seu código.

Essa discussão é bastante atual, pois a eterna luta entre a comunidade de software livre e proprietários tem suas raízes baseadas no dilema de como é possível confiar que um software faz exatamente o que se pede, quando não se pode auditar o código.

No Brasil, com a ascensão do Presidente Luiz Inácio Lula da Silva, foi determinado que no âmbito do governo federal softwares de código aberto deviam preferencialmente ser usados. Dentro do contexto de segurança, tal decisão foi extremamente acertada, porém o simples fato de se ter acesso ao software, não é garantia de que o usuário está livre de vulnerabilidades e da ocorrência de falhas de segurança.

Conforme [NIST, 2002] a segurança é um processo onde o fator humano é determinante para seu sucesso. Entre esses fatores pode-se citar como crítico as falhas causadas por usuários internos. Estudos rescentes [MÓDULO, 2003] mostram que um grande número de incidentes de segurança são causados por ações não intencionais de usuários, ou seja, erros ou falhas inseridas pelos próprios funcionários devido ao não conhecimento do sistema usado ou simples falta de disciplina e conscientização no que tange a segurança.

Apesar de a ação de coibir o uso de software proprietário ter sido correta, a forma como o trabalho foi feito apresenta sérias falhas gerenciais. A primeira delas foi a publicidade a migração. Sabe-se que o homem é muito reativo a mudanças, dessa forma uma mudança de seus hábitos diários, se não for devidamente justificada, fará com que ele seja um adversário potencial a idéia. O problema nasce que muitos usuários até hoje não vêem como necessária a migração das aplicações para código aberto, normalmente justicando sua ação em um ponto muito importante: a migração atende apenas aspectos financeiros, sem analisar aspectos produtivos.

Essa visão do problema, apesar de ser bastante simplista, não está equivocada, pois a bandeira levantada pelo Governo Federal em muitas esferas técnicas e gerenciais, apesar de todo a bandeira libertária, foi a que o uso do software livre é bom porque é mais barato que o software proprietário.

Isso não é uma verdade universal, pois os custos mudam de local. O uso de software livre, por ser mais flexível, necessita que seus administradores sejam mais flexíveis também, o que ocasiona que o custo de aquisição seja diluído nos custos de suporte técnico e treinamento. Esse fato não é um problema, pois ao invés de pagar royalts para uma empresa, muitas vezes estrangeira, o dinheiro é gasto no país, aquecendo dessa forma a economia local. Apesar dessa constatação, o que se viu nas repartições públicas não foi essa transferência de dinheiro, mas sim o simples corte de gastos.

A maior vantagem do uso de software livre é a capacidade que dá ao usuário de ter o exato conhecimento do código que está usando. Para isso deve ter conhecimento técnico suficiente para que possa analisar os diversos fontes gerados e verificar que não existem backdoors nem falhas graves de segurança. Porém esse nível de uso do software livre é bastante complicado de ser atingido, pois envolve um conhecimento técnico muito aprofundado, o que muitos órgãos governamentais não estão interessados em pagar.

Uma forma de resolver essa questão seria adotar um modelo similar ao americano, onde alguma entidade seria responsável por auditar todos os códigos utilizados pelo Governo Federal e gerar recomendações e documentos oficiais atestando a segurança da aplicação, ou seja, a não presença de bugs significativos ou cavalos de tróia.

Para que isso fosse possível, seria necessário que houvesse uma padronização dos softwares a serem usados pelas diversas entidades governamentais, o que de certa forma já é feito, pois liberdade não pode significar falta de produtividade.

Porém essa realidade está longe de estar presente. Nossas ações gerenciais e políticas no uso de software livre seja no nível de Política de Estado ou dentro das políticas locais das Instituições, ainda vêem a questão como uma mera questào financeira.

Outro fato que colaboraria para essa questão é que comunidades de software livre muito conhecidas na verdade possuem poucos profissionais com real conhecimento do código fonte que representam. Na maior parte das instituições públicas, a grande parte dos usuários são apenas administradores de sistemas, onde os desenvolvedores de aplicações usam as bibliotecas, linguagens e adaptam o código livre a suas necessidade, não havendo tradição de existirem grandes mantenedores de software básico como compiladores e sistemas operacionais. No Brasil a situação é um pouco melhor, mas não muito diferente.

Essa situação é alarmante, pois a linha de adoção do software livre usada pelo Governo Brasileiro, não resolve o problema do software proprietário, mas sim apenas mascara a questão, pois a visibilidade prometida pelo uso de software aberto está longe de ser alcançada.

Conforme comentado anteriormente, essa questão somente será resolvida quando as autoridades governamentais mudarem sua postura com relação a questão, usando como justificativa para a sua adoção os motivos que permearam o crescimento inicial da comunidade.

Referências Bibliográficas:

[THOMPSON, 1995] Ken Thompson. Reflections oon Trusting Trust. ACM, 1995.

[NIST, 2002] Risk Management Guide for Information Technology System. NIST, 2002.

[MODULO, 2003] 9a. Pesquisa Nacional de Segurança da Informação. Módulo, 2003.

segunda-feira, 4 de junho de 2007

RSA e Testes de Primalidade

1. O Algoritmo RSA

Em 1977, três pesquisadores (Rivest, Shamir e Adleman) desenvolveram um algoritmo de criptografia de chave pública baseado na dificuldade de fatorar números compostos com elevada magnitude, que foi chamado RSA.

O RSA veio a ser o primeiro modelo real, uma vez que o modelo original desenvolvido por Diffie-Helman não tinha viabilidade prática na época.

Segundo o RSA, um usuário inicial (Bob) escolhe dois primos aleatórios de grande magnitude (p e q). Ele multiplica esses valores e gera um novo número n=p*q.

De posse de n, Bob seleciona um expoente criptográfico e, tal que ele tenha a seguinte propriedade gcd (e, (p-1)(q-1)=1.

Após calcular o expoente criptográfico, Bob envia ele (e) juntamente com n para os usuários que deseja estabelecer um canal seguro.

O usuário remoto que deseja enviar uma mensagem (m) através de um canal seguro deve realizar a seguinte operação: c deve ser congruente a me (mod n), onde c é a mensagem cifrada a ser trafegada.

Ao receber a mensagem, Bob deverá calcular um valor d (secreto), tal que d*e seja congruente a 1 (mod(p-1)(q-1)), onde a mensagem em claro (m ) será congruente a cd(mod n).

2. Testes de Primalidade

Conforme pode-se ver nos parágrafos anteriores, a eficácia de uma algoritmo RSA se deve a correta seleção dos valores primos que comporão o valor de n, usado para calcular a chave pública e privada usada pelo algoritmo.

Uma das tarefas assessórias, porém tão importante como o armazenamento de forma segura dos valores p e q, são os testes que definem se um valor é primo ou não, pois caso não o seja, toda a proteção do RSA fica comprometida, pois é possível fatorar o valor de forma bastante eficiente e rápida.

2.1. Teste Fundamental de Primalidade

O teste de primalidade mais rudimentar é baseado em um teorema de primalidade. Esse teorema diz que se um valor n inteiro e positivo é composto, então ele possui um divisor primo menor ou igual a raiz quadrada de n.

Por esse teorema, se eu quero descobrir os números primos que compõe um valor n, então eu texto (força bruta) todos os valores ímpar menores que a raiz quadrada de n para verificar se dividem n.

O problema dessa abordagem é que seriam necessárias pelo menos raiz quadrada de logaritmo da raiz quadrada de n divisões para provar que um valor é primo, ou seja, é extremamente ineficiente.

2.1. Teste Fermat

O teste de fermat diz que se n é primo, para todo a pertencente ao conjunto dos inteiros existe an-1 congruente a 1 (mod n).

Caso o valor n passe em seu teste, ou seja, ele é congruente a 1, não se pode afirmar que o valor é primo, apenas diz-se que ele é provavelmente primo, uma vez que existem alguns números compostos que passam por esse teste (números de Carmichael).

Porém quando o valor de n não passa no teste, pode-se afirmar que o valor n não é primo, ou seja, é composto.

Ex.: n=341=11 * 31 => 2340 congruente a 1 (mod 341), porém 3340 é congruente a 56 (mod 341).

Um bom uso para o teste de fermat é em um teste inicial de um valor, caso ele não passe, automaticamente se define que o número é composto. Caso ele passe, deve-se executar um novo teste que será visto a seguir (o teste de Miller-Rabin).

2.2. Número de Carmichael

Um número de Carmichael é um valor que não se consegue provar pelo teste de fermat se ele é composto ou não para qualquer que seja a base utilizada.

Um exemplo de um número de Carmichael é 561, que é igual 3*11*17 e qualquer que seja a base testada, sempre retornará que o valor é primo.

2.3. Testes de Miller-Rabin

O teste de Miller-Rabin garante que um valor é primo, onde ele é totalmente imune aos números de carmichael.

Para realizar teste de miller-rabin, deve-se escolher um valor ímpar n>1, tal que n-1=m*2k e m também é um valor ímpar.

O teste consiste em selecionar um novo valor randômico a, tal que 1.

Deve-se calcular b0 congruente am (mod n). Se b0 for congruente a +/- 1 (mod n), então n é certamente composto, caso contrário, ele provavelmente seja primo e deve-se calcular um novo valor b1 congruente b02 (mod n).

Caso o valor de b0 for congruente a +/- 1 (mod n), n é composto.

Esse teste deve ser repetido várias vezes de forma a se garantir que o valor n tenha uma grande probabilidade de ser primo, uma vez que o teste miller-rabin é baseado na distribuição estatística de Monte Carlo.

Uma vez que a teoria informa que a densidade de números primos é de aproximadamente 1/ln(x). Se eu quero um x com uma grandeza aproximadamente de 100 casas decimais (x=10100), então a densidade de primos (k) é de aproximadamente 1/230. Como os primos são sempre ímpar (exceto 2), k será aproximadamente 1/100, fazendo com que seja necessário, para essa magnitude, cerca de 100 testes de miller-rabin.