Criptografia: cifra de Della Porta em Python

Giambattista della Porta ou Giovanni Batista della Porta foi um estudioso, escritor, filósofo e dramaturgo italiano.

Escreveu várias obras e, dentre elas, publicou, em 1563, uma na área de criptografia chamada De Furtivis Literarum Notis, onde descreve sua cifra de substituição polialfabética.

Esta cifra consiste numa tabela de alfabetos onde cada alfabeto tem como chave um par de letras, formando assim um total de treze alfabetos (utilizando-se o alfabeto latino). Abaixo está uma tabela que resume quais as chaves e seus alfabetos.

       A B C D E F G H I J K L M
A, B - N O P Q R S T U V W X Y Z
C, D - O P Q R S T U V W X Y Z N
E, F - P Q R S T U V W X Y Z N O
G, H - Q R S T U V W X Y Z N O P
I, J - R S T U V W X Y Z N O P Q
K, L - S T U V W X Y Z N O P Q R
M, N - T U V W X Y Z N O P Q R S
O, P - U V W X Y Z N O P Q R S T
Q, R - V W X Y Z N O P Q R S T U
S, T - W X Y Z N O P Q R S T U V
U, V - X Y Z N O P Q R S T U V W
W, X - Y Z N O P Q R S T U V W X
Y, Z - Z N O P Q R S T U V W X Y

Como exemplo, vamos cifrar a palavra guerra, utilizando a chave F. Neste caso, será utilizado o alfabeto da linha 3 (E, F). Assim, g torna-se V, u torna-se F, e torna-se T, r torna-se C e a torna-se P. A mensagem, cifrada, fica VFTCCP. Utilizando-se somente uma letra como chave, fica similar à cifra de César. Mas o objetivo desta cifra não é este, mas sim usar uma palavra como chave. Então, vamos escolher a frase O ataque será amanhã e a palavra-chave FERIAS.

  texto plano - o a t a q u e s e r a a m a n h a
        chave - F E R I A S F E R I A S F E R I A
texto cifrado - M P L R D L T D Z A N W O P F Y N

Observe que a palavra-chave foi repetida até que todos os caracteres da mensagem a ser cifrada tivessem uma letra da palavra-chave correspondente. Para cifrar, pegamos o primeiro caracter da mensagem, a letra o, checamos qual a letra da palavra-chave (letra F), buscamos na tabela qual alfabeto será usado (linha 3 – E, F) e vemos qual letra corresponde para trocar (letra M). O processo é repetido para cada letra da mensagem. Note que se as letras sempre serão trocadas entre as letras no cabeçalho da tabela. Desta forma, a mensagem cifrada fica MPLRDLTDZANWOPFYN.

CÓDIGOS

Desta vez, resolvi criar uma classe separada que pretendo utilizar em outras cifras. Será uma classe básica com alguns métodos que serão utilizados mais frequentemente. Dei-lhe o nome de Cipher e a salvei no arquivo cipher.py.

# -*- coding: utf-8 -*-
class Cipher(object):
    def format_str(self, text):
        '''
        Limpa text dos espacos em branco e retorna em
        maiusculas
        '''
        return text.replace(' ', '').upper()

A classe DellaPorta é a responsável por fazer a cifragem/decifragem e herda de Cipher (ambas devem estar no mesmo diretório para que funcione) e está salva no arquivo della_porta.py.

[Atualização 16/01/2015]

Alterado o método repeat_password.

# -*- coding: utf-8 -*-
from cipher import Cipher

class DellaPorta(Cipher):
    ''' Cifra criptografica de Giambattista della Porta '''
    def __init__(self):
        '''
        keys - chaves para determinar o deslocamento da cifra
        plain - alfabeto fixo
        cipher - alfabeto a ser deslocado
        '''
        self.keys = {
            'A': 0, 'B': 0, 'C': 1, 'D': 1, 'E': 2, 'F': 2,
            'G': 3, 'H': 3, 'I': 4, 'J': 4, 'K': 5, 'L': 5,
            'M': 6, 'N': 6, 'O': 7, 'P': 7, 'Q': 8, 'R': 8,
            'S': 9, 'T': 9, 'U': 10, 'V': 10, 'W': 11,
            'X': 11, 'Y': 12, 'Z': 12
        }
        self.plain = 'ABCDEFGHIJKLM'
        self.cipher = 'NOPQRSTUVWXYZ'

    def shift(self, key):
        ''' Desloca o alfabeto '''
        shift = self.keys[key]
        return self.cipher[shift:] + self.cipher[:shift]

    def repeat_password(self, password, length):
        ''' Repete a password ate o tamanho do texto plano '''
        new_pass = password * (length/len(password))
        length -= len(new_pass)
        if length:
            new_pass += password[:length]
        return new_pass

    def encrypt(self, plaintext, password):
        ''' Retorna o texto cifrado '''
        ciphertext = ''
        plaintext = self.format_str(plaintext)
        plainalphabet = self.plain
        password = self.format_str(
            self.repeat_password(password, len(plaintext))
        )
        for idx in range(len(plaintext)):
            char = plaintext[idx]
            cipheralphabet = self.shift(password[idx])
            if char in plainalphabet:
                idchar = plainalphabet.find(char)
                ciphertext += cipheralphabet[idchar]
            elif char in cipheralphabet:
                idchar = cipheralphabet.find(char)
                ciphertext += plainalphabet[idchar]
        return ciphertext

    def decrypt(self, ciphertext, password):
        ''' Retorna o texto decifrado '''
        return self.encrypt(ciphertext, password)

E, para testes, o arquivo teste_della_porta.py que testa nossa classe DellaPorta, solicitando uma frase a ser cifrada e a senha.

# -*- coding: utf-8 -*-
from della_porta import DellaPorta
import sys

versao = sys.version_info[0]

if versao == 2:
    leitura = raw_input
elif versao == 3:
    leitura = input

txt_in = leitura('Texto a ser cifrado: ')
txt_key = leitura('Chave: ')

dporta = DellaPorta()
txt_cifrado = dporta.encrypt(txt_in, txt_key)
print('')
print('Texto cifrado: {0}'.format(txt_cifrado))
print('  Texto plano: {0}'.format(dporta.decrypt(txt_cifrado, txt_key)))

TESTES

Como teste vamos utilizar o exemplo dado acima. Cifraremos a frase ‘o ataque sera amanha’ e com a senha ‘ferias’. Executando o arquivo teste_della_porta.py, temos:

Texto a ser cifrado: o ataque sera amanha
Chave: ferias

Texto cifrado: MPLRDLTDZANWOPFYN
  Texto plano: OATAQUESERAAMANHA

FONTES
http://ruffnekk.stormloader.com/porta_info.html
http://www.numaboa.com.br/criptografia/58-criptologia-historia/344-Della-Porta
http://www.numaboa.com.br/criptografia/cifras/substituicoes/polialfabeticas/345-della-porta
http://practicalcryptography.com/ciphers/classical-era/porta/
http://pt.wikipedia.org/wiki/Giovanni_Battista_della_Porta
http://en.wikipedia.org/wiki/Giambattista_della_Porta

Sobre Fábio Medeiros

Meu nome é Fábio Medeiros. Cearense de nascença e com muito orgulho (daí o nome do blog, uma referência à minha terra). Sou formado em Tecnologia em Telemática, pelo CEFET-CE. Escrevi alguns artigos sobre programação JavaME e dispositivos portáteis (PDA) para a revista WebMobile.
Esse post foi publicado em Criptografia e marcado , , . Guardar link permanente.

Uma resposta para Criptografia: cifra de Della Porta em Python

  1. Pingback: Criptografia: cifra de Vigenère em Python | siriarah

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s