Encriptação - Chave Simétrica - psql

PostgreSQL no Raspberry Pi com FreeBSD 13

Usando o PostgreSQL no Raspberry Pi com FreeBSD 13, vamos mostrar como armazenar com segurança os dados das contas de vários sites numa tabela do PostgreSQL, com as informações encriptadas usando uma chave simétrica PGP especificada na instrução SQL.

Os algoritmos de chave simétrica são algoritmos de criptografia que utilizam as mesmas chaves criptográficas tanto para a encriptação de texto simples quanto para a desencriptação de texto criptográfico. Pretty Good Privacy (PGP) é um programa de encriptação que fornece privacidade criptográfica e autenticação para a comunicação de dados.

Para trabalhar com o PostgreSQL vamos utilizar o psql, que permite digitar comandos interativamente, submetê-los para o PostgreSQL, e ver os resultados no terminal.

Extensão pgcrypto

A primeira coisa a ser feita é se conectar ao PostgreSQL e criar a extensão pgcrypto, que fornece funções de criptografia para o PostgreSQL.

halley@bsd:~ $ psql --username=pguser --host=raspberry.pi --dbname=pgbase --password
Password: 
psql (13.3)
Type "help" for help.

pgbase=> CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION

Criar a tabela

Vamos criar a tabela sites para armazenas os dados das conexões com os sites e conceder permissões para o usuário halley:

pgbase=> DROP TABLE IF EXISTS sites;
DROP TABLE
pgbase=> CREATE TABLE IF NOT EXISTS sites (
    id      SERIAL NOT NULL            ,             -- Identificador da linha
    login   VARCHAR(255) NOT NULL DEFAULT user,      -- Usuário que efetuou o login no PostgreSQL
    titulo  TEXT   NOT NULL,                         -- Título do site (Google, Yahoo, etc.)
    url     TEXT   NOT NULL DEFAULT 'Não fornecido', -- URL do site
    usuario TEXT   NOT NULL DEFAULT 'Não fornecido', -- Nome da conta no site (nome, e-mail, telefone, etc.)
    senha   TEXT   NOT NULL DEFAULT 'Não fornecido', -- Senha da conta no site
    notas   TEXT   NOT NULL DEFAULT 'Não fornecido', -- Informações extras
    CONSTRAINT pk_sites PRIMARY KEY (id)             -- Chave primária
);
CREATE TABLE
pgbase=> -- Só um título por login
pgbase=> ALTER TABLE sites
    ADD CONSTRAINT unique_login_titulo
    UNIQUE  (login, titulo);
ALTER TABLE
pgbase=> -- Conceder permissões para o usuário 'halley'
pgbase=> GRANT ALL ON sites TO halley;
GRANT
pgbase=> GRANT ALL ON sites_id_seq TO halley;
GRANT

Preencher a tabela com dados encriptados

Vamos inserir informações na tabela sites para um usuário do Google e outro do Yahoo. Para encriptar os dados vamos usar a função PGP_SYM_ENCRYPT de pgcrypto, que encripta dados empregando algoritmo de chave simétrica.

pgbase=> INSERT INTO sites (titulo, url, usuario, senha, notas) VALUES(
'Google',
PGP_SYM_ENCRYPT('https://www.google.com.br/', 'Minh4Senh@Fort3')::text,       -- Encrypt data with a symmetric PGP key psw.
PGP_SYM_ENCRYPT('usuario_google', 'Minh4Senh@Fort3')::text,                   -- Encrypt data with a symmetric PGP key psw.
PGP_SYM_ENCRYPT('senha_google', 'Minh4Senh@Fort3')::text,                     -- Encrypt data with a symmetric PGP key psw.
PGP_SYM_ENCRYPT('Minhas observações sobre o Google', 'Minh4Senh@Fort3')::text -- Encrypt data with a symmetric PGP key psw.
);
INSERT 0 1
pgbase=> INSERT INTO sites (titulo, url, usuario, senha, notas) VALUES(
'Yahoo',
PGP_SYM_ENCRYPT('https://br.yahoo.com/', 'Minh4Senh@Fort3')::text,            -- Encrypt data with a symmetric PGP key psw.
PGP_SYM_ENCRYPT('usuario_yahoo', 'Minh4Senh@Fort3')::text,                    -- Encrypt data with a symmetric PGP key psw.
PGP_SYM_ENCRYPT('senha_yahoo', 'Minh4Senh@Fort3')::text,                      -- Encrypt data with a symmetric PGP key psw.
PGP_SYM_ENCRYPT('Minhas observações sobre o Yahoo', 'Minh4Senh@Fort3')::text  -- Encrypt data with a symmetric PGP key psw.
);
INSERT 0 1

Consultar a tabela

Vamos fazer uma consulta para listar os dados inseridos. Para desencriptar os dados vamos usar a função PGP_SYM_DECRYPT de pgcrypto, que desencripta dados encriptados com chave simétrica.

pgbase=> SELECT id, login, titulo,
PGP_SYM_DECRYPT(url::bytea, 'Minh4Senh@Fort3') as url,                        -- Decrypt a symmetric-key-encrypted PGP message.
PGP_SYM_DECRYPT(usuario::bytea, 'Minh4Senh@Fort3') as usuario,                -- Decrypt a symmetric-key-encrypted PGP message.
PGP_SYM_DECRYPT(senha::bytea, 'Minh4Senh@Fort3') as senha,                    -- Decrypt a symmetric-key-encrypted PGP message.
PGP_SYM_DECRYPT(notas::bytea, 'Minh4Senh@Fort3') as notas                     -- Decrypt a symmetric-key-encrypted PGP message.
FROM sites;
 id | login  | titulo |            url             |    usuario     |    senha     |               notas               
----+--------+--------+----------------------------+----------------+--------------+-----------------------------------
  1 | pguser | Google | https://www.google.com.br/ | usuario_google | senha_google | Minhas observações sobre o Google
  2 | pguser | Yahoo  | https://br.yahoo.com/      | usuario_yahoo  | senha_yahoo  | Minhas observações sobre o Yahoo
(2 rows)

Se for feita uma consulta sem usar a senha vão ser mostrados os dados criptografados.

pgbase=> SELECT senha FROM sites;
                                                                             senha                                                                              
----------------------------------------------------------------------------------------------------------------------------------------------------------------
 \xc30d040703020f732e2f31ca183879d23d0171263b82a3e91d9385a53fe98a1a61c8f361c436ab0785abc833d57c19f058f961a6fb46c32b8ec783942f504ec94f5bf4327da8ad17454dab801577
 \xc30d04070302cb546bae4064a40969d23c019db2095b630b78031a6c2712af6341fb588f34817fe96f0df5f18fae179bc78b9529fee9939f6f095a7d8fcada7dda1e87add8fe43d96a9dadfb8f
(2 rows)

Encriptação múltipla

A encriptação múltipla é o processo de encriptar uma ou mais vezes uma mensagem já encriptada, utilizando o mesmo algoritmo, ou um algoritmo diferente.

Como os dados são encriptados com uma chave simétrica PGP, há possibilidade de serem hackeados através de um ataque de força bruta. Para aumentar a segurança, podemos encriptar os dados duas vezes com duas chaves diferentes, como mostrado abaixo:

pgbase=> \set primeira_senha 'Minh4Primeir@Senh@Fort3'
pgbase=> \set segunda_senha 'Minh4Segund@Senh@Fort3'
pgbase=> INSERT INTO sites (titulo, url, usuario, senha, notas) VALUES (
'Google',
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('https://www.google.com.br/', :'primeira_senha')::text, :'segunda_senha')::text,
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('usuario_google', :'primeira_senha')::text, :'segunda_senha')::text,
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('senha_google', :'primeira_senha')::text, :'segunda_senha')::text,
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('Minhas observações sobre o Google', :'primeira_senha')::text,  :'segunda_senha')::text
);
INSERT 0 1
pgbase=> INSERT INTO sites (titulo, url, usuario, senha, notas) VALUES (
'Yahoo',
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('https://br.yahoo.com/', :'primeira_senha')::text, :'segunda_senha')::text,
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('usuario_yahoo', :'primeira_senha')::text, :'segunda_senha')::text,
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('senha_yahoo', :'primeira_senha')::text, :'segunda_senha')::text,
PGP_SYM_ENCRYPT(PGP_SYM_ENCRYPT('Minhas observações sobre o Yahoo', :'primeira_senha')::text,  :'segunda_senha')::text
);
INSERT 0 1

Para ler os dados é necessário desencriptar duas vezes, usando as chaves em ordem inversa:

pgbase=> SELECT id, login, titulo,
PGP_SYM_DECRYPT(PGP_SYM_DECRYPT(url::bytea, :'segunda_senha')::bytea,:'primeira_senha') AS url,
PGP_SYM_DECRYPT(PGP_SYM_DECRYPT(usuario::bytea, :'segunda_senha')::bytea, :'primeira_senha') AS usuario,
PGP_SYM_DECRYPT(PGP_SYM_DECRYPT(senha::bytea, :'segunda_senha')::bytea, :'primeira_senha') AS senha,
PGP_SYM_DECRYPT(PGP_SYM_DECRYPT(notas::bytea, :'segunda_senha')::bytea, :'primeira_senha') AS notas
FROM sites;
 id | login  | titulo |            url             |    usuario     |    senha     |               notas               
----+--------+--------+----------------------------+----------------+--------------+-----------------------------------
  1 | pguser | Google | https://www.google.com.br/ | usuario_google | senha_google | Minhas observações sobre o Google
  2 | pguser | Yahoo  | https://br.yahoo.com/      | usuario_yahoo  | senha_yahoo  | Minhas observações sobre o Yahoo
(2 rows)

Se for feita uma consulta sem usar as senhas vão ser mostrados os dados criptografados.

pgbase=> SELECT senha FROM sites;
                                                                                                                                                                                                                                senha                                                                                                                                                                                                                                 
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 \xc30d04070302ed3ab5b1f1bd3ff864d2c00f01f2245054eca3a7d4c7d2d8703b7e5a64e86d8cb7895cc5d7dce875c05196c7689d9235d90e40c19df834b30651524d2f3c98ee67bd7f336d325a5706e6483f2d56eb53cdf5f52159b1897e12c5c6c434a3e1c75ded70ca34b2a611feaba0041ffdc002c81da3e9d2ded2de19c0507fea3da885afdbb2d495df3097a0fd28950ac9898c0ff680ce20dac21503dfa45000cb248df0a67d66f7a1e8921d2ca98bcc4e3d31f8d91255a05fc5ec9420d12d87511a9cb009ecb567b347fbcac3b084da8c0121e896ef35201abb0126026a
 \xc30d04070302b3472d444ce5afb87ad2c00d01ea7f25f0ace350fc3cfe5edf08a6cbe72068816db2cc280bd911422f1359f5c57ac49d5c5d460956a489b81610b25cd6a9c0889595205ac8c784cf7cbd465d1e4a6ec77f6095798551ac78c32cf03f6dd32d4689261f1e6c323bc302dc00ea89a5a4ce1b404e4f34a9e9a0e9b4727f9293d3db7c0e24cb99a60f64f06468fd82adc13257f12b5a767af9724874ad3a5c016ff0c631a8e669ab24924db1c973ec96ed2831312e913e8726069ab98b9558a1f3c5bd7358c41382abc16ac8ffbf719de61615174b998e0cd48f31
(2 rows)

Referência

* * *