4D Write Pro – Assinar e proteger documentos

O objetivo deste artigo é mostrar como, de uma forma fácil de implementar, é possível assinar e verificar documentos de forma transparente.
O benefício óbvio dessa abordagem é a paz de espírito quando os documentos forem abertos novamente, com a certeza de que não foram modificados nesse meio tempo.

Isso é especialmente importante se armazenar documentos 4D Write Pro como modelos inteligentes contendo código 4D como arquivos externos no disco. Antes de executar esse código, quer ter certeza que o arquivo não foi modificado externamente.

Ou, no caso de documentos externos, ter certeza que vieram do remetente certo e não foram alterados durante sua jornada digital.
O princípio que vamos descrever aplica-se aos documentos 4D Write Pro, mas aplica-se a qualquer outro tipo de documento com algumas pequenas modificações.

Exemplo de base de dados

Encriptação ou assinatura?

Aqui, vamos concentrar-nos na autenticação de um documento, ou seja, como ter a certeza de que não foi modificado entre o momento em que foi registado pelo seu proprietário original (legal/oficial/etc.) e o momento em que é lido pelo seu destinatário (ou relido pelo seu proprietário!). Não estamos a falar de encriptação, embora isso também possa ser feito, mas esse é outro assunto! (Se estiver interessado em criptografia, consulte este BLOG)

Criar uma assinatura.

O processo de criação de uma assinatura é bastante simples: a partir do documento original, criamos uma assinatura baseada no documento completo (como um BLOB) utilizando uma chave “privada”. Esta assinatura (e apenas esta) será armazenada no próprio documento, normalmente no final do documento.

Reler a assinatura

Antes de abrir o documento, a assinatura oficial é relida. Será criado um novo BLOB a partir de todo o documento (sem a chave de fim, portanto teoricamente idêntico ao original) e será verificado, desta vez utilizando uma chave pública, intimamente ligada à chave privada que foi utilizada para criar a assinatura. O resultado desta verificação determinará o que acontece de seguida!

Nesta fase, há três possibilidades…

Partimos do princípio de que o documento está assinado, mas não é necessariamente esse o caso. Se o documento não contiver uma assinatura, é necessário ter cuidado, embora não seja necessariamente corrupto.
Abrir ou não o documento depende do programador, do usuário, das circunstâncias, do ambiente… Em suma, é preciso decidir o que fazer!

A segunda possibilidade é que a assinatura corresponda ao conteúdo. Boas notícias, então. Pode ter a certeza de que o documento é aquele que criou ou que lhe foi confiado/enviado/etc. e, sobretudo, que não foi alterado desde a sua criação. Isto significa que pode abri-lo com toda a tranquilidade, desde que, evidentemente, confie no remetente. Pode então modificá-lo, guardá-lo, assiná-lo novamente ou não, consoante a sua utilização futura. Se tiver de a modificar e depois a devolver ao remetente, é aconselhável assiná-la, para que o futuro destinatário possa efetuar a mesma operação.

Finalmente, a terceira possibilidade é que o documento possa ter sido alterado (ou mesmo corrompido) durante a transferência. A mais pequena vírgula acrescentada ou retirada, a mais pequena fórmula modificada, etc., fará com que a assinatura deixe de corresponder!
Saberá imediatamente, para poder tomar as medidas adequadas.

Vamos começar!

Neste exemplo, vamos assinar um ou mais arquivos existentes já guardados no formato 4D Write Pro, ou seja, com uma extensão . “4wp”. Como vamos gerenciar arquivos, vamos usar as classes 4D.File e 4D.FileHandle. E como vamos gerir chaves de encriptação, assinatura e verificação, também vamos usar 4D.CryptoKey (veja o BLOG correspondente se ainda não está familiarizado com estas classes…).

SAFE Criar chaves padrão

Antes de mais, vamos criar um par de chaves privadas/públicas e guardá-las de uma vez por todas como uma entidade na base de dados (este par de chaves será usado como chaves “default” mais tarde, como exemplo).

$cryptoKey:=ds.CryptoKey.new()
$keyOptions:={type: "RSA"; size: 2048}
$key:=4D.CryptoKey.new($keyOptions)

$cryptoKey.privateKey:=$key.getPrivateKey()
$cryptoKey.publicKey:=$key.getPublicKey()

$cryptoKey.save()

Documento SAFE Sign

A seguir, é necessário adicionar uma assinatura ao final de um arquivo (4D.File) usando uma chave privada.
Para resumir, aqui está o que precisa fazer:

// cria uma nova chave baseada em chave privada
$keyOptions:={type: "PEM"; pem: $privateKey}
$key:=4D.CryptoKey.new($keyOptions)

//…
// cria a assinatura com a função .sign()
$signOptions:={hash: "SHA512"; encodingEncrypted: "Base64URL"}
$signature:=$key.sign($documentAsBlob; $signOptions)

// anexa a assinatura (como um BLOB) no final do documento
TEXT TO BLOB($signature; $blobSignature; UTF8 text without length)
$fileHandle.offset:=$documentSize
$fileHandle.writeBlob($blobSignature)

SAFE Verificar assinatura

Finalmente, ANTES de abrir o documento, precisa verificar sua assinatura. Isto é feito pelo seguinte método, que recebe um arquivo (4D.File) e, opcionalmente, uma chave pública

// criar uma nova chave baseada em chave pública
$signOptions:={hash: "SHA512"; encodingEncrypted: "Base64URL"}
$type:={Type; "PEM"; pem; $publicKey}
$key:=4D.CryptoKey.new($type)

// ler a assinatura real 	
//…
$fileHandle.offset:=$documentSize-$length
$blobSignature:=$fileHandle.readBlob($length)
$textSignature:=BLOB to text($blobSignature; UTF8 text without length)

// checar a assinatura usando a função .verify()
$check:=$key.verify($documentAsBlob; $signature; $signOptions)
If ($check.success)
	$result:=1
Else 
	$result:=-1
End if 

Isso funciona com .4wp, mas e quanto a outros documentos?

Quando 4D Write Pro carrega um documento .4wp, o fim do documento é automaticamente detectado para que saiba onde parar. A assinatura adicionada ao final do arquivo não o interrompe. Por outras palavras, quer o documento esteja assinado ou não, quer a assinatura esteja correta ou não, o .4wp será carregado sem qualquer problema, daí a necessidade de verificar previamente a sua assinatura.

Para outros tipos de documentos, é possível (ou mesmo provável) que a adição de uma assinatura no final perturbe o carregamento, pelo que pode ser necessário – depois de o validar, claro – remover a assinatura.

Documento SAFE Unsign

Por esta razão, este outro método foi criado para efetuar a operação oposta.
Remove a assinatura de um documento para o repor no seu estado original e, se o documento não estiver assinado, simplesmente não faz nada.

$fileHandle:=$file.open("write")  
//…  calcula o tamanho da assinatura e…
$fileHandle.setSize($documentSize-$length)

Conclusão

Este exemplo simples mostra como assinar um documento e verificar a assinatura antes de o abrir. Quando se trocam documentos entre dois sítios, são necessários dois pares de chaves públicas/privadas, mas o princípio continua a ser o mesmo. O criador do documento assina com uma chave privada e o leitor verifica-a com a chave pública fornecida pelo criador.
As chaves públicas e privadas são bens preciosos, permitindo tanto a assinatura como a autenticação, razão pela qual é aconselhável guardá-las no próprio ficheiro de dados!

Roland Lannuzel
- Proprietário do produto & Especialista 4D - Depois de estudar electrónica, a Roland entrou nas TI industriais como desenvolvedor e consultor, construindo soluções para clientes com uma variedade de bases de dados e tecnologias. No final dos anos 80, apaixonou-se pela 4D e utilizou-a para escrever aplicações comerciais que incluem sistemas de contabilidade, facturação e correio electrónico. Juntando-se à empresa em 1997, as valiosas contribuições de Roland incluem a concepção de especificações, ferramentas de teste, demonstrações, bem como formação e palestras para a comunidade 4D em muitas conferências. Ele continua a moldar activamente o futuro da 4D, definindo novas características e ferramentas de desenvolvimento de bases de dados.