terça-feira, 24 de agosto de 2010

Criptografia Assimétrica

Este artigo aplica-se aos seguintes produtos e tecnologias:

• Microsoft .Net Framework 2.0

Introdução

Este artigo é uma continuação de “Criptografia e Certificação Digital”.

Criptografia Assimétrica

Como citado no primeiro artigo desta série, a criptografia de dados usando algoritmos assimétricos dispõe de um par de chaves publica/privada. Quando o dado é criptografado com a chave pública, somente que tem a chave privada pode descriptografar. Esse algoritmo é muito utilizado quando a informação se externa ao sistema e é necessário manter um grau de segurança nos dados, e para que não seja divulgada uma única chave como é feito nos algoritmos simétricos, possuímos um par, e esse é divulgado somente a parte pública.

Imagine o seguinte cenário: Você precisa trocar informações confidenciais com alguns usuários sem precisar divulgar a chave de criptografia que utiliza. Para isso, é criado um par de chaves onde somente uma será divulgada para os usuários que você deseja receber a informação.



Ilustração 1 – Visualização da criptografia assimétrica.

O exemplo de código a seguir exemplifica o cenário mencionado usando o algoritmo RSA. Primeiramente o usuário “UserA” distribui a sua chave pública para aqueles que ele deseja receber a informação de forma segura. Em seguida o “UserB” codifica a mensagem com a chave pública enviada pelo “UserA”. Ressalto que somente quem tem a chave particular “UserA” poderá ler a mensagem.

Exemplos de código


//Instancia a classe RSA
RSACryptoServiceProvider rsaProviderGen = new RSACryptoServiceProvider();

// Obtém os pares de chaves
string publicKey = rsaProviderGen.ToXmlString(false);
string privateKey = rsaProviderGen.ToXmlString(true);
Console.WriteLine(String.Format("{0}{1}\n","Chave Pública.....:", publicKey));
Console.WriteLine(String.Format("{0}{1}\n","Chave Particular..:", privateKey));

// Mensagem a ser Cifrada
string messageToEncr = "Olá Mundo;)";
Console.WriteLine(String.Format("{0}{1}\n","Texto Plano.......:", messageToEncr));

// UserB gera a mensagem cifrada para o UserA utilizando a Chave Pública que lhe foi passada

RSACryptoServiceProvider rsaProviderEncr = new RSACryptoServiceProvider();
rsaProviderEncr.FromXmlString(publicKey);
byte[] messageToDencr = rsaProviderEncr.Encrypt(Encoding.Unicode.GetBytes(messageToEncr),false);
Console.WriteLine(String.Format("{0}{1}\n","Texto Cifrado.....:", System.Convert.ToBase64String(messageToDencr)));

// UserA lê a mensagem utilizando a sua chave partitular
RSACryptoServiceProvider rsaProviderDencr = new RSACryptoServiceProvider();
rsaProviderDencr.FromXmlString(privateKey);

string
plainMessage = Encoding.Unicode.GetString(rsaProviderDencr.Decrypt(messageToDencr,false));
Console.WriteLine(String.Format("{0}{1}\n","Texto Plano.....:", plainMessage));

Dica

Se o “UserA” precisa enviar informações para o “UserB”, é necessário que o “UserB” também crie seu par de chaves. Assim o “UserA” passa a utilziar a chave pública do “UserB” para cifrar a informação.

Links Relacionados

.NET Framework Cryptography Model

Bibliografia Utilizada

• Building Secure ASP.NET Applications, Microsoft Patterns & Practices

domingo, 8 de agosto de 2010

Criptografia Simétrica



Este artigo aplica-se aos seguintes produtos e tecnologias:

• Microsoft .Net Framework 2.0

Introdução

Este artigo é uma continuação de “Criptografia e Certificação Digital”.

Criptografia Simétrica

Como citado no primeiro artigo desta série, a criptografia de dados usando algoritmos simétricos dispõe de uma única chave para criptografar e descriptografar a informação, sendo assim, somente aqueles que possuem acesso à chave podem ler e escrever neste formato de dados.

Imagine o seguinte cenário: Você deseja sigilo nas informações gravadas pelo seu sistema no banco de dados ou então geradas em disco. É comum que administradores de sistemas, de banco de dados, usuários avançados, desenvolvedores e analistas tenham acesso a informação, muitas vezes confidencial, como por exemplo, dados de cartão de crédito, dados bancários, senhas, etc. Para isso a utilização de algoritmos simétricos seria uma escolha inteligente, visto que propicia uma criptografia ágil e segura, escondendo a informação de qualquer acesso não autorizado.
Ilustração 1 – Visualização da criptografia simétrica.

O exemplo de código a seguir exemplifica o cenário mencionado usando o algoritmo Rijndael. O usuário “UserA” cifra a mensagem com a chave e grava no banco de dados. Somente quem conhece a chave e o algoritmo pode recuperar o dado cifrado.

Exemplos de código

// Exemplo usando o algoritmo Rijndael
var cryptoProvider = new RijndaelManaged();

cryptoProvider.GenerateKey();
cryptoProvider.GenerateIV();

byte[] key = cryptoProvider.Key;
byte[] IV = cryptoProvider.IV;

// Define a mensagem
string messageToEncr = "Olá Mundo;)";
Console.WriteLine( String.Format("{0}{1}","Texto Plano..:", messageToEncr));

// Criptografa
string messageToDencr = Encry(messageToEncr, key, IV);
Console.WriteLine( String.Format("{0}{1}","Texto Cifrado:", messageToDencr));


// Descriptografa os dados
string dencrMessage = Dencry(messageToDencr, key, IV);
Console.WriteLine(String.Format("{0}{1}","Texto Plano..:", dencrMessage));

As classes possuem métodos para gerar a chave e o vetor de inicialização que devem ser armazenadas em local seguro, para que seja possível recuperar a o dado cifrado no futuro. No exemplo acima uso a própria classe para gerar, mas caso você já tenha a chave, o que é o mais comum, pode utilizá-las conforme o trecho de código seguinte:

// Chave de criptografia
string MyKey = "M!n8Ch@v3";

// Exemplo usando o algoritmo Rijndael
var cryptoProvider = new RijndaelManaged();

// Usando a chave e o IV derivado da chave
PasswordDeriveBytes pdb = new PasswordDeriveBytes(MyKey, new MD5CryptoServiceProvider().ComputeHash(Encoding.Unicode.GetBytes(MyKey)));

byte[] key = pdb.GetBytes(32);
byte[] IV = pdb.GetBytes(16);

// Define a mensagem 
string messageToEncr = "Olá Mundo;)";
Console.WriteLine(String.Format("{0}{1}", "Texto Plano..:", messageToEncr));

// Criptografa 
string messageToDencr = Encry(messageToEncr, key, IV);
Console.WriteLine(String.Format("{0}{1}", "Texto Cifrado:", messageToDencr));

Não é recomendada a utilização do mesmo vetor de inicialização (VI) para cifrar outros dados, pois se perde o sentido do algoritmo, visto que o vetor de inicialização serve para oferecer a aleatoriedade nos dados gerados.

O método Encry

static string Encry(string plainText, byte[] key, byte[]IV)
{
    RijndaelManaged cryptoProvider = new RijndaelManaged();
    ICryptoTransform cryptoTrans = cryptoProvider.CreateEncryptor(key,IV);

    // Utiliza a classe CryptoStream para transformar o texto plano
    MemoryStream ms = new MemoryStream();
    CryptoStream cryptStream = new CryptoStream(ms, cryptoTrans, CryptoStreamMode.Write);
    StreamWriter sw = new StreamWriter(cryptStream);
    sw.Write(plainText);

    // Fecha Streams
    sw.Close();
    cryptStream.Close();
    ms.Close();

    // Obtém o texto cifrado
    return System.Convert.ToBase64String(ms.ToArray());
}

O método Dencry

static string Dencry(string cipherText, byte[] key, byte[] IV)
{
    RijndaelManaged cryptoProvider = new RijndaelManaged();

    // Utiliza a classe CryptoStream para transformar o texto cifrado
    MemoryStream ms =
new
MemoryStream(System.Convert.FromBase64String(cipherText));

    CryptoStream cryptStream = new CryptoStream(ms, cryptoProvider.CreateDecryptor(key,
IV), CryptoStreamMode.Read);


    StreamReader sr = new StreamReader(cryptStream);
    string descryptedMessageText = sr.ReadToEnd();
    // Fecha Streams    sr.Close();
    cryptStream.Close();
    ms.Close();

    // Obtém o texto plano
    return descryptedMessageText;
}


Chaves

Alguns algoritmos suportam chaves de até 1024bits, porém a maioria das classes implementam até 256bits. Segue algumas informações relacionadas ao tamanho das chaves para cada algoritmo:

• RC2: chaves de 40 a 128 bits
• DES: chaves de 64 bits
• Rijndael: chaves de 128, 192 ou 256(Padrão) bits
• TripleDES: chaves de 128 até 192 bits

Dica

Observe o exemplo da figura “Ilustração – 1”, a senha é a mesma para os dois usuários. Isso significa que embora os usuários sejam diferentes ambos possuem a mesma senha. Isso caracteriza um risco para seu ambiente, ou seja, se um determinado usuário atualizar a senha do usuário “root” com a sua senha pessoal, ele terá acesso de login com as credencias do usuário “root”, pois não há nenhuma inteligência para gerar a chave que cifra os dados. Tente sempre utilizar alguma outra informação junto com a chave de criptografia, ou gerar um IV diferente, como por exemplo, usando o nome do usuário, isso fará com que embora eles tenham a mesma senha, terão valores criptografados diferentes.

Links Relacionados

.NET Framework Cryptography Model

Bibliografia Utilizada

• Building Secure ASP.NET Applications, Microsoft Patterns & Practices

quinta-feira, 8 de julho de 2010

Dicas - Manipulação de Caminhos no ASP.NET

///<summary>
///Classe utilitária que oferece suporte a manipulação dos caminhos virtuais.
///</summary>
class System.Web.VirtualPathUtility

Referências:

quarta-feira, 7 de julho de 2010

Criptografia e Certificação Digital

Este artigo aplica-se aos seguintes produtos e tecnologias:

• Microsoft .Net Framework 2.0

Resumo

Este artigo apresenta uma visão geral das classes de criptografia e certificação digital do .Net Framework, fornecendo subsídios para auxiliar na escolha correta de um mecanismo para criptografia e segurança de dados.

Introdução

Em nossa área, são freqüentes as dificuldades em escolher ou até mesmo compreender alguns conceitos de criptografia no .NET. É de conhecimento notório para muitos programadores o namespace “System.Security.Cryptography”, todavia o que gera dúvidas é a correta utilização das classes de criptografia em cada um dos cenários que enfrentamos em nosso dia-a-dia. Desta forma, este namespace proporciona uma série de classes que dão suporte a criptografia e, até mesmo, a utilização de assinaturas digitais. O presente artigo abordará uma visão geral e introdutória sobre as classes de criptografia em que são utilizados os algoritmos simétricos, assimétricos, Hash e, por fim, as assinaturas digitais.

Princípios

Atualmente, utiliza-se a criptografia para assegurar três princípios básicos e inerentes à informação: Sigilo, Integridade e Autenticidade.

No que concerne ao sigilo, o objetivo é ocultar ou dificultar o acesso às informações confidenciais. Já em relação à integridade, busca-se assegurar que a informação é confiável e não foi alterada ou modificada de forma “maliciosa” e, por fim, no que se refere à autenticidade, visa-se garantir que a origem da informação seja conhecida e atestada.

Criptografia

Como citado no início, o namespace “System.Security.Cryptography” fornece uma série de classes que dão suporte aos mais diversos algoritmos de criptografia. Estas classes, porém são abstratas e, por sua vez, implementadas de acordo com os diagramas seguintes.

Ilustração 1 - Diagrama de classes para criptografia assimétrica

Os algoritmos assimétricos são indicados e se apresentam como os mais adequados para viabilizar a troca de informação em meios inseguros, nos quais cada participante possui um par de chaves, uma pública e outra particular.

Nesse caso, quem utiliza a chave pública para criptografar os dados deve utilizar a particular para descriptografar e vice-versa. Sendo assim, se o usuário distribuir a chave pública, qualquer pessoa poderá gerar informações, as quais somente o usuário que tem a chave particular poderá ler.

Por outro lado, se o usuário gerar os dados com a chave particular, todos que têm acesso a chave pública poderão descriptografar os dados.
Ilustração 2 - Diagrama de classes para criptografia simétricas

Por sua vez, o uso de algoritmos simétricos permite uma criptografia rápida, já que utiliza algoritmos de complexidade simples e chaves menores. Neste caso, cada usuário deverá utilizar a mesma chave para ler e gerar as informações.
Ilustração 3 - Diagrama de classes para criptografia Hash

Já os algoritmos de Hash oferecem suporte à integridade dos dados, garantido que a informação não tenha sido adulterada durante a sua passagem entre os diversos meios.

Certificados e Assinaturas Digitais

Dentro do namespace “System.Security.X509Certificates” encontramos as classes que dão suporte aos certificados digitais. Um certificado do tipo “X509” contém, além das informações de usuário, outros tipos de dados, como por exemplo, o e-mail, informações para assinatura digital e etc. Este tipo de certificado é assinado digitalmente por um terceiro (CA – Certification Authority) que garante a autenticidade deste certificado.

Existem muitos motivos para a utilização de certificados digitais. O usuário pode utilizar este tipo de certificado para autenticar serviços, aplicativos, clientes, assinar digitalmente documentos, sites e aplicações seguras (SSL), IPSec e etc.

Quando usamos um certificado digital para assinarmos digitalmente algum arquivo, um hash deste arquivo é gerado e criptografado com as informações contidas no certificado digital. Assim o receptor do arquivo garante autenticidade, pois confia em quem autenticou o certificado digital e sabe que a informação mantém-se íntegra, pois através do certificado consegue validar o hash do arquivo.

Conclusão

Considerando que o objetivo deste artigo é apresentar uma breve introdução das classes de criptografia do .NET, auxiliando os desenvolvedores na escolha do algoritmo conveniente no contexto do software e abrindo caminho para que nos próximos artigos sejam abordadas algumas de suas implementações, já podemos observar, de imediato, a versatilidade e o leque de opções disponíveis no .Net para segurança e criptografia de dados.

Links Relacionados


Bibliografia Utilizada

• Building Secure ASP.NET Applications, Microsoft Patterns & Practices

domingo, 27 de junho de 2010

Trabalhando com grandes tipos de dados

Este artigo aplica-se aos seguintes produtos e tecnologias:

• Microsoft SQL Server 2005
• Microsoft SQL Server 2008

Introdução

É fato que, atualmente, as colunas do tipo varchar, nvarchar, varbinary e XML podem se tornar verdadeiros pesadelos para desenvolvedores e administradores de banco de dados, se, durante a fase de arquitetura de seus respectivos bancos, não forem limitados seu tamanho.

Ademais, é sabido que somente as informações carregadas do disco para memória podem ser manipuladas pelo Sistema de Gerenciamento de Banco de Dados (SGBD). Assim, se pudéssemos de alguma maneira organizar estes tipos de dados em outra página de dados o SGBD poderia armazenar uma quantidade maior de informação em uma única página, ou seja, em uma página de 8k poderiam ser armazenados mais registros se estes tipos de campos fossem armazenados em uma extensão desta página.

Os resultados de tais suposições seria a possibilidade de armazenar mais dados, ocorrendo menos I/O de disco e menos processamento, eis que seria necessário carregar menos páginas para resgatar as informações mais relevantes de uma tabela.

Isso pode se tornar útil em cenários onde não é possível redefinir a estrutura de tabelas ou então um grande volume de I/O de disco e memória deve ser reduzido.

Neste artigo tentarei explicar o comando sp_tableoption e a opção large value types out of row e suas implicações.

Opções de Configuração de Tabela

O comando sp_tableoption é um comando que pode ser usado para determinar o comportamento dos registros de uma tabela. Especificamente para campos do tipo varchar, nvarchar, varbinary e XML.

Sintaxe:

sp_tableoption [ @TableNamePattern = ] 'table'
, [ @OptionName = ] 'option_name'
, [ @OptionValue = ] 'value'

A opção large value types out of row, é responsável por determinar se os tipos de dados varchar, nvarchar, varbinary e XML devem ser ou não armazenados na mesma página de dados da tabela.
O valor padrão é ‘OFF’, desta maneira os dados são contidos na mesma página de dados junto com os demais campos da tabela.

Já o valor ‘ON’ determina que estes campos devem permanecer em uma extensão da página de dados.
Também, existe a opção de informarmos um valor de bytes entre 24 e 7000. Isso delimita a quantidade de bytes que será armazenado no registro.

O valor configurado para a opção pode ser verificado consultando a tabela sys.tables e observado o valor da coluna large_value_types_out_of_row. O valor 1 indica que está ‘ON’.

A Tabela Customers

Adicionei na tabela “Customers” do banco de dados “Northwind” o campo “Comments”.

Alter Table Customers Add Comments nvarchar(Max) null
go
Update Customers Set Comments = 'Microsoft SQL Server Microsoft SQL Server Microsoft SQL Server Microsoft Microsoft SQL Server Microsoft SQL Server Microsoft SQL Server Microsoft Microsoft SQL Server'

Observe a nova definição da tabela:



Figura 1 – resultado do comando sp_help Customers.


Nesse momento é importante obtermos algumas estatísticas de I/O, referentes a algumas consultas nesta tabela:

Set nocount on
go
Set Statistics io on
go
select * From Customers

Table 'Customers'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

O dado mais importante para nós é exibido em “logical reads” e “lob logical reads”. O primeiro indica quantas páginas da memória foram lidas para formar o resultado. O Segundo informa quantas extensões da página de dados ou large object binary foram lidos para formar o resultado.

Para resgatar as informações dos clientes é necessário consultar nove páginas de dados. Isso significa que as informações do campo Comments estão definitivamente na mesma página de dados com o restante das informações, pois nenhum outro tipo de página foi lido.

Também, executando a seguinte consulta, isso fica mais claro.

set nocount on
go
Set Statistics io on
go
select
CustomerID
,CompanyName
,ContactName
,ContactTitle
,Address
,City
,Region
,PostalCode
,Country
,Phone
,Fax
From Customers

Table 'Customers'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Podemos observar que as mesmas nove páginas foram lidas, mesmo removendo a coluna Comments da consulta.

Armazenando Grandes Valores Fora dos Registros

No cenário acima é preciso ler as nove páginas da tabela Customers, mesmo não utilizando a coluna Comments. Observe agora, quando utilizamos a opção de manter os grandes tipos de dados em outra página.

Alter Table Customers Add Comments nvarchar(Max) null
go
Exec sp_tableoption
@TableNamePattern = 'Customers'
,@OptionName = 'large value types out of row'
,@OptionValue = 'ON'
go
Update Customers Set Comments = 'Microsoft SQL Server Microsoft SQL Server Microsoft SQL Server Microsoft Microsoft SQL Server Microsoft SQL Server Microsoft SQL Server Microsoft Microsoft SQL Server'

Executamos a consulta à tabela Customers novamente e obtemos o seguinte resultado:

set nocount on
go
Set Statistics io on
go
select * From Customers

Table 'Customers'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 192, lob physical reads 0, lob read-ahead reads 0.

Note que foram necessárias somente seis páginas para armazenar as informações da tabela Customer e outras 192 páginas para armazenar os dados da coluna Comments. As informações agora estão sendo armazenadas em outra estrutura, permitindo que mais dados sejam adicionados nas mesmas páginas de dados. Isso permite que dados mais relevantes e mais registros estejam na mesma página.

Se consultarmos todas as colunas com exceção da coluna Comments obtemos um valor de leitura de páginas de somente seis leituras lógicas. O que não seria possível se os dados da coluna Comments estivessem na mesma página de dados.

set nocount on
go
Set Statistics io on
go
select
CustomerID
,CompanyName
,ContactName
,ContactTitle
,Address
,City
,Region
,PostalCode
,Country
,Phone
,Fax
From Customers

Table 'Customers'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

O resultado é uma economia de leitura de três páginas. Isso para uma tabela com pouquíssimos registros.

Links Relacionados

MSDN sp_tableoption
MSDN text in row option

Conclusão

A utilização e otimização de recursos avançados é uma necessidade no cenário mundial, principalmente diante de necessidades cada vez maiores do setor tecnológico. Todavia, tal situação deve ser avaliada com cuidado, principalmente levando em consideração o cenário em questão. Há muitos outros fatores que impactam no desempenho de I/O de páginas de dados, podemos citar além deste, a fragmentação, o fator de preenchimento e outros.

Verificando as informações do artigo, constatamos que podemos armazenar mais informações relevantes dentro de uma página de dados, quando armazenamos campos do tipo varchar, nvarchar, varbinary e XML fora da estrutura da tabela.

São comuns termos campos de “Observações”, “Comentários” e etc. Para estes casos, onde a maioria das consultas não os utiliza, podemos usar a opção large value types out of row para aperfeiçoar essas consultas.

Com isso, conseguimos diminuir I/O de disco e memória, e processamento, visto que podemos retornar mais informação consultando menos páginas de dados.

domingo, 20 de junho de 2010

Sobre

Olá,

Sou Giovani Decusati atuo na área de informática desde 2000, especializando-me na área de desenvolvimento de sistemas e arquitetura de banco de dados. Utilizo as tecnologias Microsoft como Visual Fox Pro, Visual Studio .NET, SQL Server e Windows Server para construir e projetar soluções para as empresas das mais diversas áreas e ramos de atuação. Trabalho em projetos cliente/servidor e n-camadas tanto para desktop quanto para web. Além disso, obtive a credencial MCDBA de forma que possuo, também, experiência na administração de ambientes Windows Server 2003, SQL Server 2000 e no desenvolvimento com .Net Framework. Atualmente trabalho na CWI Software na área de desenvolvimento de sistemas.

Meu objetivo com o blog é expressar minha opinião sobre tecnologia e contribuir para a comunidade através da publicação de artigos e dicas das tecnologias Microsoft.