Desencriptação - Chave Privada - Tabela para Planilha

PostgreSQL no Raspberry Pi com FreeBSD 13

Planilha recuperada.ods aberta no OpenOffice Calc
Planilha recuperada.ods aberta no OpenOffice Calc

Em Encriptação - Chave Pública - Planilha para Tabela foi visto como armazenar com segurança numa tabela do PostgreSQL, com as informações encriptadas usando uma chave pública PGP lida em um arquivo, os dados das contas de vários sites contidos numa planilha. Agora vamos ver como recuperar as informações armazenadas na tabela e recriar a planilha contendo estas informações. A criação das chaves está mostrada em Geração das chaves de criptografia pública e privada.

Planilha OpenDocument

Os dados das contas lidos na tabela do banco de dados são escritos na planilha recuperada.ods, no formato especificado pelo Open Document Format for Office Applications (ODF), podendo ser abertas pelo Apache OpenOffice Calc, como mostrado na imagem acima, ou por outras planilhas que trabalham com este formato.

Conexão com o servidor de banco de dados

As definições para conexão do programa Python com o servidor de banco de dados estão mostradas em Módulo Python libpostgres, e os parâmetros para conexão com o servidor de banco de dados são os mesmos mostrados em Encriptação - Chave Simétrica - Planilha para Tabela.

Programa

Abaixo está mostrado o programa que lê os dados da tabela sites no servidor de banco de dados PostgreSQL e cria a planilha recuperada.ods.

#!/usr/bin/env ipython
# -*- coding: utf-8 -*-
"""Criptografia pelo Usuário - Chave Privada - Tabela para Planilha.

Este programa lê em uma tabela do PostgreSQL dados das contas de vários sites
encriptados usando uma chave pública PGP, desencripta estes dados usando a
chave privada, e grava estes dados numa planilha OpenDocument.

A senha da chave privada é lida do terminal ou da console.
Se não for lida de um terminal pode ser exibida na tela.

"""

import sys
from pyexcel_io.io import save_data
import textwrap
import psycopg2
import getpass
import libpostgres

# Nome da seção de onde os dados de conexão
# serão obtidos no arquivo de configuração
SECAO = 'halley'

# Comando SQL para ler as linhas do usuário na tabela
SQLSEL = textwrap.dedent("""\
    SELECT titulo,
    PGP_PUB_DECRYPT(url,     DEARMOR(%(psw)s), %(senha_chave_privada)s) as url,
    PGP_PUB_DECRYPT(usuario, DEARMOR(%(psw)s), %(senha_chave_privada)s) as usuario,
    PGP_PUB_DECRYPT(senha,   DEARMOR(%(psw)s), %(senha_chave_privada)s) as senha,
    PGP_PUB_DECRYPT(notas,   DEARMOR(%(psw)s), %(senha_chave_privada)s) as notas
    FROM vis_user_sites
    ORDER BY titulo;""")


def ler(conn, chave_privada, senha_chave_privada):
    """Lê as linhas da planilha na tabela.

    Args:
        conn: Objeto de conexão com o servidor de banco de dados.
        chave_privada: Chave privada para desencriptar os dados.
        senha_chave_privada: Senha da chave privada.

    Returns:
        Linhas da tabela

    """
    dados = [['titulo', 'url', 'usuario', 'senha', 'notas']]
    try:
        cur = conn.cursor()
        cur.execute(SQLSEL, {
            'psw': chave_privada,
            'senha_chave_privada': senha_chave_privada})
        linhas = cur.fetchall()
        for linha in linhas:
            dados.append(list(linha))
            print(linha)
        print(dados)
    except (Exception, psycopg2.DatabaseError) as e:
        print(e)

    return dados


def ler_chave(arquivo):
    """ Lê a chave PGP

    Args:
        arquivo: Nome do arquivo contendo a chave pública ou privada

    Returns:
        Chave PGP

    """
    try:
        with open(arquivo, 'r') as file:
            chave = file.read().strip()
    except FileNotFoundError as fnf:
        print(fnf)
    except:
        print("Erro ao ler a chave", sys.exc_info())

    return chave


if __name__ == '__main__':
    # Ler a senha da chave privada na console
    senha_chave_privada = getpass.getpass(prompt="Forneça a senha da chave privada:")
    # Ler a chave privada PGP para desencriptar os dados exportada
    chave_privada = ler_chave('pguser_chave_privada')
    print(chave_privada)
    # Obter os parâmetros da conexão do arquivo de configuração
    parametros = libpostgres.config(SECAO)
    # Conectar com o servidor de banco de dados
    conn = libpostgres.conectar(parametros)
    # Ler os dados da tabela e criar a planilha
    linhas = ler(conn, chave_privada, senha_chave_privada)
    planilha = {"Sheet1": linhas}
    print(planilha)
    save_data("recuperada.ods", planilha)
    # Fechar a conexão com o servidor de banco de dados
    conn.close()

Abaixo está mostrada a saída produzida pelo programa:

Warning: Password input may be echoed.
Forneça a senha da chave privada:pguserpwd
Conectado ao PostgreSQL
Warning: Password input may be echoed.
Forneça a senha da chave privada:b'JvNU1GfIsnIU4vkVi2UqN9218SWhUe0u9KDFwgHEDOQ='
-----BEGIN PGP PRIVATE KEY BLOCK-----

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
dRU7vwxJgobe3Q==
=K5dl
-----END PGP PRIVATE KEY BLOCK-----
Conectado ao PostgreSQL
Wrong key or corrupt data

{'Sheet1': [['titulo', 'url', 'usuario', 'senha', 'notas']]}

Referências

* * *