Olá amigos,
É com muita honra que aceitei ser colunista do ActiveDelphi.
Minha primeira matéria como colunista será uma dica simples, mas de muita utilidade.
Certa vez, criando um software para laboratórios farmacêuticos, me deparei com uma estrutura de dados intrincada, que levaria muito tempo para ser elaborada em um banco de dados e elevaria a complexidade do banco ao extremo.
Para complicar, todos os dados
deveriam ser criptografados e assinados. Eu tinha em mãos um enigma:
Um produto químico possuía um teste.
Cada teste possuía 5 tipos de ambientes climáticos.
O primeiro ambiente, possuía 3 períodos em meses.
O segundo, 6 períodos.
Os restantes, mais de 10 períodos.
Cada análise feita em um teste de um período, possuía mais "N" tipos de
subtestes e cada subteste, mas "N" resultados.
E tudo isso deveria ser confidencial, e portanto, criptografado e assinado
digitalmente.
Como é um sistema de worflow, a informação deveria estar disponível de forma
rápida e confiável.
Então, tive a idéia de criar estruturas do tipo RECORD, para armazenar os dados,
estipulando valores máximos para os itens variáveis.
Fui criando estruturas básicas de RECORDS e colocando umas dentro das outras,
usando ARRAYS quando necessário, até chegar ao RECORD TTeste.
Minha visão era a de ter uma única variável em que eu pudesse trabalhar, para
criptografar e assinar todos os dados de uma única vez. O armazenamento no banco
de dados, dessa forma, seria em um único passo, o que acabaria tornando o
sistema mais confiável resistente a falhas de gravação.
Mas como gravar tudo isso em um banco de dados?
Resolvi então criar um campo BLOB no banco de dados, criptografar os dados,
assinar, e gravar em um único passo.
Desfazer a operação também seria simples e rápido.
Criei um DEMO para ilustrar este método, que poderá ser copiado no link
http://www.activedelphi.com.br/imagens/artigos/criptografia/salvadados.zip
O DEMO foi criado para o banco de dados Interbase e o arquivo GDB deverá residir
no mesmo diretório do executável.
Descrição da operação:
Passo 1:
Criar campos relevantes em uma tabela no banco de dados, e mais um campo do tipo
BLOB SUB_TYPE TEXT, para armazenar os dados da estrutura.
Passo 2:
Na operação de gravar, criei um MemoryStream, passei os dados da estrutura para
o stream.
St := TMemoryStream.Create;
St.Write(Teste, SizeOf(Teste) );
St.Position := 0;
Passo 3:
Gravei o stream no campo BLOB.
TBlobField(Tabela01.FieldByName('CAMPOBLOB')).LoadFromStream(St);
Pronto.
E para que a estrutura (que estava com quase 4Mb) ficasse bem no banco de dados,
que ainda passei por um stream de compactação da ZLIB, que o reduziu para 490
Kb...
Para desfazer, é só gravar o BLOB no stream e deste para a variável:
St := TMemoryStream.Create;
TBlobField(Tabela01.FieldByName('CAMPOBLOB')).SaveToStream(St);
St.Position := 0;
St.Read(Teste, SizeOf(Teste) );
Este método pode não ser novidade para muita gente, mas achei que seria
útil divulgá-lo.
Existem algumas implicações:
Para localizar o registro mais tarde, os campos que classificam o registro devem
estar TAMBÈM fora da estrutura, em um campo convencional. É útil realizar uma
verificação se o campo fora da estrutura é igual ao que está dentro no
momento de abrir-lo, para evitar que alguém tente modificar a informação.
Este método vai na contra-mão dos bancos de dados relacionais, então eu
aconselho a utilizá-lo somente quando a complexidade justificar.
No meu caso, eu deveria criar várias tabelas relacionadas e talvez algumas
dúzias de campos array no Interbase. A criptografia e assinatura digital
ficariam fora de cogitação.
Carlos Magno Abreu é desenvolvedor de sistemas e criptógrafo.
Sua principal área de atuação é desenvolver sistemas que envolvam
segurança avançada, sistemas de autenticação e assinaturas digitais.
Trabalhou no Centro de Análises de Sistemas Navais (CASNAV), desenvolvendo
sistemas de comunicação e segurança.
|