Criptografia: cifra de Vigenère em Python

A cifra de Vigenère (atribuída equivocadamente a Blaise de Vigenère) foi descrita primeiramente pelo italiano Giovan Battista Bellaso, em 1553, em sua obra La cifra del. Sig. Giovan Batista Bellaso e por muito tempo foi considerada como le chiffre indéchiffrable (a cifra indecifrável) quando, em meados do século XIX,  Charles Babbage e Friedrich Kasiki encontraram um método de resolvê-la.

É uma cifra polialfabética e seu funcionamento vai lembrar um pouco a cifra de Trithemius, só que a cifra de Vigenère utiliza uma chave para cifrar uma mensagem, e um pouco da cifra de Della Porta, só que para cada letra da chave corresponde um alfabeto diferente.

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

O processo de cifragem utiliza uma chave que se não tiver o mesmo tamanho do texto a ser cifrado deve ser repetida até que o texto plano e a chave tenham o mesmo tamanho. Por exemplo, tomemos como texto plano há um espião entre nós e a chave hoplita:

texto plano - haumespiaoentrenos
      chave - hoplita

Veja que o texto plano tem 18 letras e a chave tem 7 letras, assim, vamos repetir a chave hoplita até chegarmos ao tamanho de 18 letras. Ficando assim:

texto plano - haumespiaoentrenos
      chave - hoplitahoplitahopl

Agora com a chave de tamanho igual ao texto plano começamos o processo de cifragem. Utilizando a primeira letra do texto plano (h) como coluna e a primeira letra da chave (h) como linha, encontramos na interseção a letra O, que é a letra cifrada de h com o alfabeto h.

  texto plano - haumespiaoentrenos
        chave - hoplitahoplitahopl
texto cifrado - O

A segunda letra do texto plano (a) utilizará o alfabeto da segunda letra da cifra (o), resultando na letra O novamente.

  texto plano - haumespiaoentrenos
        chave - hoplitahoplitahopl
texto cifrado - OO

O processo se repetirá para todas as letras do texto plano.

  texto plano - haumespiaoentrenos
        chave - hoplitahoplitahopl
texto cifrado - OOJXMLPPODPVMRLBDD

Neste nosso exemplo o texto plano há um espião entre nós será cifrado como OOJXMLPPODPVMRLBDD.

CÓDIGOS

Alterei a classe base Cipher (criada no post da cifra de Della Porta) e a salvei no arquivo cipher.py.

# -*- coding: utf-8 -*-
class Cipher(object):
    """ Classe base para as cifras classicas """
    def format_str(self, text):
        '''
        Retorna text sem espacos e em maiusculas
        '''
        return text.replace(' ', '').upper()

    def shift_alphabet(self, alphabet, shift):
        '''
        Retorna alphabet com deslocamento de valor shift
        '''
        return alphabet[shift:] + alphabet[:shift]

A classe Vigenere é a responsável pela cifragem e decifragem e está salva no arquivo vigenere.py.

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

class Vigenere(Cipher):
    """ Cifra de Vigenere """
    def __init__(self):
        self.plain = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

    def repeat_password(self, password, text):
        '''
        Repete a password ate o tamanho de text
        '''
        if len(password) < len(text):
            new_pass = password * (len(text)/len(password))
            if len(new_pass):
                new_pass += password[:len(new_pass)]
            return new_pass.upper()
        return password.upper()

    def encrypt(self, plaintext, password, decrypt=False):
        '''
        Cifra plaintext com a cifra de Vigenere
        Decifra se decrypt for True
        '''
        password = self.repeat_password(password, plaintext)
        plaintext = self.format_str(plaintext)
        textout = ''
        for idx, char in enumerate(plaintext.upper()):
            # indice da letra da cifra
            idx_key = self.plain.find(password[idx])
            # gera alfabeto cifrado
            c_alphabet = self.shift_alphabet(self.plain, idx_key)

            if decrypt:
                idx_p = c_alphabet.find(char)
                textout += self.plain[idx_p]
            else:
                idx_p = self.plain.find(char)
                textout += c_alphabet[idx_p]

        return textout

    def decrypt(self, ciphertext, password):
        '''
        Decifra ciphertext
        '''
        return self.encrypt(ciphertext, password, True)

TESTES

Para teste criamos o arquivo teste_vigenere.py que chama a classe Vigenere.

# -*- coding: utf-8 -*-
from vigenere import Vigenere
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: ')
password = leitura('Senha: ')

cifra = Vigenere()
txt_cifrado = cifra.encrypt(txt_in, password)
print
print('Texto cifrado: {0}'.format(txt_cifrado))
print('  Texto plano: {0}'.format(cifra.decrypt(txt_cifrado, password)))

Vamos testar a cifra com a frase no dia dez o ataque sera pelo norte e senha armagedom.

Texto a ser cifrado: no dia dez o ataque sera pelo norte
Senha: armagedom

Texto cifrado: NFPIGHHNAAKMQAIVSDAGQLURRFFE
  Texto plano: NODIADEZOATAQUESERAPELONORTE

FONTES

http://pt.wikipedia.org/wiki/Cifra_de_Vigenère
http://en.wikipedia.org/wiki/Vigenère_cipher
http://www.numaboa.com.br/criptografia/cifras/substituicoes/polialfabeticas/506-vigenere

Publicado em Criptografia | Marcado com , | Deixe um comentário

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

Publicado em Criptografia | Marcado com , , | 1 comentário

Convertendo livros em ePub para o Kindle com o kindlegen

Ultimamente compro meus eBooks na Amazon e leio-os no aplicativo Kindle para iPad. Uma das características que me levou a adotar o Kindle foi a sincronia que ele permite para livros pessoais enviados para a Amazon Cloud Drive. Sincroniza a última página de leitura, anotações e marcações.

Só que há aqueles que possuem livros no formato ePub (não suportado pelo Kindle) e eu mesmo disponibilizo alguns livros no formato ePub. Este pequeno tutorial tem por objetivo converter um livro no formato ePub para o formato Kindle.

O aplicativo utilizado será o kindlegen, desenvolvido pela própria Amazon. É um aplicativo de linha de comando, com versão para Windows, Linux e Mac OS. Disponível aqui.

Os livros convertidos pelo kindlegen contêm, num mesmo arquivo, os dois formatos suportados pelo Kindle, o formato KF8 e o Mobi. Então não há a necessidade de preocupação com qual Kindle (aplicativo ou ereader) o livro será lido.

Todos os comandos indicados no tutorial servem para qualquer versão utilizada.

Vamos utilizar, como exemplo, o ePub da Bíblia ACF 2007 (que pode ser baixado aqui no blog mesmo :) ). O nome do arquivo é ACF2007.epub.

Depois de baixado o kindlegen, descompacte o arquivo baixado e, no diretório onde ele foi descompactado, copie o arquivo ACF2007.epub (só para facilitar o trabalho).

CONVERTENDO DE EPUB PARA O FORMATO KINDLE

Para converter o arquivo, abra o prompt de comando ou o terminal e digite:

kindlegen ACF2007.epub

A conversão pode demorar dependendo do tamanho do arquivo ePub.

Terminada a conversão, haverá a criação de um arquivo ACF2007.mobi, com tamanho 7619 kB. O tamanho é maior que o ePub, pois o arquivo mobi gerado, como falei, contêm os dois formatos de livros Kindle, o KF8 (mais novo) e o Mobi (mais antigo, herança do Mobipocket).

COMPRESSÃO DO FORMATO KINDLE

Há algumas opções que podem ser aplicadas na conversão do arquivo e que o deixarão com tamanho menor. Uma delas é ativar a compressão do arquivo. O kindlegen nos permite três tipos:

  • sem compressão (opção -c0);
  • compressão padrão DOC (opção -c1; esta opção é utilizada mesmo que não se passe por parâmetro ao kindlegen);
  • compressão Kindle Huffdic (opção -c2)

Assim, para converter o arquivo ePub com a compressão Kindle huffdic utilizamos o comando abaixo:

kindlegen -c2 ACF2007.epub

Esta opção irá demorar mais para converter o livro, mas ele ficará com tamanho um pouco menor. Em termos de comparação veja a tabela abaixo quando utilizamos as diversas opções de compressão:

FORMATO|TAMANHO|COMPRESSÃO
 ePub  | 1520KB|-----
 Mobi  |14187KB|sem compressão
 Mobi  | 7619KB|compressão padrão DOC
 Mobi  | 5188KB|compressão Kindle huffdic

REMOVENDO OS ARQUIVOS FONTE DO FORMATO KINDLE

Quando um arquivo é convertido para o formato Kindle, são adicionados ao arquivo final, os arquivo fonte (source) que são utilizados para a construção final do arquivo, o que torna o tamanho final do arquivo mobi maior. Para não adicionar estes arquivos basta usar a opção -dont_append_source como parâmetro ao kindlegen, como mostrado no comando abaixo:

kindlegen -c2 -dont_append_source ACF2007.epub

Abaixo uma tabela comparando o tamanho dos arquivos gerados:

FORMATO|TAMANHO|SOURCE|COMPRESSÃO
 Mobi  | 5188KB|  NÃO |Kindle Huffdic
 Mobi  | 3669KB|  SIM |Kindle Huffdic

 

Publicado em Tutorial | Marcado com , , , | Deixe um comentário

Atualização na Bíblia ACF 2007 e remoção da ACF 1994

Há alguns meses, a SBTB entrou em contato comigo para falar um pouco do blog. E, nesta conversa, foi-me solicitado que removesse a versão 1994 da ACF, tendo em vista que o texto da 2007 já foi lançado para substituir essa edição (embora já exista a ACF 2011, mas como não tive acesso ao texto, nem me foi autorizado nada, a 2007 continua sendo a edição mais nova disponibilizada aqui no blog). Assim, a partir de hoje, disponibilizarei somente a versão da ACF 2007 e aproveito para liberar uma nova versão nos formatos ePub e mobi com pequenas correções e acréscimos, citados abaixo:

  • (correção) nome do livro de Miquéias;
  • (correção) remoção de espaços em branco entre alguns capítulos de salmos;
  • (adição) atendendo o pedido do leitor André, adicionei no Salmo 119, subtítulos com os nomes das letras em hebraico.
Publicado em Bíblia | Marcado com , , | Deixe um comentário

Criptografia: Cifra de Trithemius ou Tabula Recta em Python

No século XV o monge alemão Johannes Trithemius desenvolveu um cifra de criptografia polialfabética. Descrita em um de seus livros, o terceiro volume de uma série, esta cifra recebe o nome de Tabula Recta.

A Tabula Recta consiste numa tabela de 26×26 preenchida da seguinte maneira: a primeira linha (1) é preenchida com o alfabeto latino em ordem alfabética. A segunda linha (2) é o mesmo alfabeto só que deslocado uma casa para a esquerda. A terceira linha (3) é deslocada em mais uma casa e assim por diante até chegarmos a 25 deslocamentos. No 26º deslocamento o ciclo se reinicia voltando-se à configuração inicial da primeira linha (1).

  |A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|
-------------------------------------------------------
 1|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|
 2|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|
 3|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|
 4|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|
 5|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|
 6|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|
 7|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|
 8|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|
 9|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|
10|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|
11|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|
12|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|
13|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|
14|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|
15|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|
16|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|
17|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|
18|R|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|
19|S|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|
20|T|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|
21|U|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|
22|V|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|
23|W|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|
24|X|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|
25|Y|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|
26|Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|

Para cifrar uma mensagem basta começar com a primeira letra da mensagem e a primeira linha da tabela (a linha não numerada corresponde ao alfabeto plano, as demais são os alfabetos cifrados). Para cada letra adicional da mensagem pulamos para a linha seguinte até chegarmos ao final das linhas da tabela onde o ciclo se reinicia. Tomemos por exemplo a palavra guerra.

primeira letra - G
primeira linha - G -> G
segunda letra - U
segunda linha - U -> V
terceira letra - E
terceira linha - E -> G
quarta letra - R
quarta linha - R -> U
quinta letra - R
quinta linha - R -> V
sexta letra - A
sexta linha - A -> F

Assim, a palavra guerra, cifrada, fica GVGUVF. Observe que na cifra de Trithemius a primeira letra da mensagem não sofre alteração, o que facilita na decifragem da mensagem caso a pessoa saiba que foi utilizada esta cifra.

CÓDIGO

Abaixo há a classe Trithemius (salva no arquivo trithemius.py) e um arquivo para teste da cifra (arquivo teste_trithemius.py). A classe ignora espaços em branco e não trata caracteres especiais.

Classe Trithemius

# -*- coding: utf-8 -*-
import string

class Trithemius(object):
    '''
    Classe de cifra Trithemius
    '''
    def __init__(self):
        self.plain = string.ascii_uppercase
        self.cipher = string.ascii_uppercase

    def shift(self):
        '''
        Desloca o alfabeto cifrado em uma casa.
        '''
        self.cipher = self.cipher[1:] + self.cipher[:1]

    def encrypt(self, text, decrypt=False):
        '''
        Cifra text com a cifra de Trithemius.
        Se decrypt é True, decifra ao invés de cifrar o text.
        '''
        text = text.replace(' ', '')
        ret_text = ''
        for char in text.upper():
            if decrypt:
                idx = self.cipher.find(char)
                ret_text += self.plain[idx]
            else:
                idx = self.plain.find(char)
                ret_text += self.cipher[idx]
            self.shift()
        self.cipher = string.ascii_uppercase
        return ret_text

    def decrypt(self, text):
        '''
        Decifra text com a cifra de Trithemius.
        '''
        return self.encrypt(text, True)

BitBin

Arquivo para teste

# -*- coding: utf-8 -*-
from trithemius import Trithemius
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: ')

trit = Trithemius()
txt_cifrado = trit.encrypt(txt_in)
print('Texto cifrado: {0}'.format(txt_cifrado))
print('Texto plano: {0}'.format(trit.decrypt(txt_cifrado)))

TESTE

Abaixo reproduzo a saída dos testes feito com a palavra guerra.

Texto a ser cifrado: guerra
Texto cifrado: GVGUVF
Texto plano: GUERRA

FONTES
http://www.numaboa.com.br/criptografia/substituicoes/polialfabeticas/805-trithemius
http://www.numaboa.com.br/criptografia/historia/347-segredo-trithemius
http://www.numaboa.com.br/criptografia/criptoanalise/1055-analise-trithemius
http://en.wikipedia.org/wiki/Tabula_recta
http://en.wikipedia.org/wiki/Trithemius_cipher

Publicado em Criptografia | Marcado com , , | 1 comentário

Token USB para GnuPG

Como já disse anteriormente, terminei uma especialização na área da criptografia e meu TCC foi sobre o GnuPG. Não pretendo aqui descrever a ferramenta, quem sabe mais para a frente, mas o que eu quero mostrar é como ter um token USB (como daqueles que podem ser adquiridos para certificado digital aqui no Brasil) para usar com o GnuPG.

Resolvi dividir o assunto em algumas partes para não ficar muito grande, assim, nesta primeira parte, mostro o equipamento adquirido, instalação dos drivers necessários para o uso e um teste rápido do produto.

As chaves do GnuPG ficam armazenadas no computador onde foi instalado e também podem ser armazenadas em um smart card, necessitando-se de um leitor de smart card para fazer a leitura do cartão.

Isto acaba tornando o uso das chaves com smart card pouco prático. Mas, caso se utilize um token USB, basta que o computador no qual desejamos utilizar o token tenha uma porta USB (e claro o driver apropriado do dispositivo :) ).

No momento há um projeto chamado Crypto Stick que está fabricando um dispositivo que possa ser utilizado como um token USB com suporte ao GnuPG. Recentemente eles disponibilizaram uma versão beta para quem quisesse adquirir o produto e que tem suas especificações mostradas aqui.

Mas existe um outro projeto, conhecido por OpenPGP Card, que é um smart card com suporte ao GnuPG, produzido pela g10code, uma empresa de consultoria na área de segurança fundada pelo criador do GnuPG. Há dois modelos de cartão: um similar àqueles de cartão de crédito e outro em que o chip é destacável, ficando no formato de um SIMCard.

Com este chip destacável, podemos utilizar um token USB que é produzido pela Gemalto, uma empresa que vende produtos voltados para segurança digital. O produto dela que serve para nossa finalidade é o IDBridge K30 ou USB Shell Token v2.

Adquiri um cartão e um token no site da Kernel Concepts. O cartão foi a versão com a opção de destaque do chip e o token foi o branco transparente (existe também uma versão em preto transparente).

Instalando o driver no Windows

Antes de utilizar o token, precisamos instalar o driver, que possui versões para Windows 32 ou 64 bits e está disponível aqui.

Baixei a versão Windows 64 bits  com o nome GemPcCCID_en-us_64.msi (observe que há para duas versões de Windows, uma em françês e outra em inglês; escolhi a inglês). A instalação é simples, basta seguir as indicações do instalador. Terminada esta parte vamos testar o token.

Instalando o driver no Linux

Também sou um usuário Linux, neste caso, utilizo o Lubuntu 14.04. De acordo com o site da Gemalto basta instalar a biblioteca libccid. Mas, eu descobri durante o teste, que se faz necessário uma outra biblioteca, a pcscd, pois sem ela não há comunicação com o leitor USB. Para isso proceda assim:

sudo apt-get install libccid pcscd

Testando o token USB

Com o token conectado na porta USB, abra o prompt de comando (ou terminal no Linux :) ) e digite (lembre-se que o GnuPG deve estar já instalado no sistema):

gpg --card-status

Algo similar ao resultado abaixo deve ser mostrado:

Application ID ...: D2760001240102000005000021150000
Version ..........: 2.0
Manufacturer .....: ZeitControl
Serial number ....: 00002115
Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: 2048R 2048R 2048R
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

onde[1]:
Application ID – a identificação do fabricante, incluindo o tipo de cartão, a versão da implementação, o fabricante e o número serial. Este identificador é único para cada cartão.
Version – especificação OpenPGP usada.
Manufacturer – O fabricante do cartão.
Serial number – número único para todos os cartões deste fabricante.
Name of cardholder – o titular deste cartão. Somente caracteres ASCII são aceitos. gpg não usa este campo.
Language prefs – preferência de linguagem do titular do cartão. gpg ignora este valor.
Sex – Masculino ou feminino. gpg ignora este valor.
URL of public key – usado pelo comando fetch do gpg –edit-card. Pode conter uma URL que pode ser usada para recuperar a chave pública.
Login data – este campo pode ser usado para armazenar o nome da conta do titular. Pode ser usado para fins de identificação. gpg não aplica qualquer correspondência deste nome com um nome usado na chave. Veja a fonte (app-openpgp.c) para algumas características especiais do campo de login-name.
Signature PIN – quando configurado para “forced”, gpg solicita a entrada de um PIN para cada operação de assinatura. Quando configurado para “non forced”, gpg pode armazenar em cache o PIN pelo tempo em que o cartão não seja removido do leitor.
Key attributes – atributos das chaves.
Max. PIN lengths – este campo é imutável. Os valores são colocados no cartão logo após a personalização – este é o momento após o chip ser colado no cartão.
PIN retry counter – este campo salva quantas tentativas ainda restam para digitar o PIN correto. São diminuídas sempre que um PIN errado for inserido. Eles são repostos sempre que um AdminPIN correto for inserido. O primeiro e segundo PIN são para o PIN padrão. gpg garante que os dois números são sincronizados. O segundo PIN só é necessário devido às peculiaridades da norma ISO-7816; gpg tenta manter este PIN em sincronia com o primeiro PIN. O terceiro PIN representa o contador de repetição para o AdminPIN.
Signature counter – Este número mantém o controle das assinaturas realizadas com a chave armazenada. Ele só é reposto se uma nova chave de assinatura é criada ou importada para o cartão.
Signature key – esta chave é comumente usada como chave primária do OpenPGP.
Encryption key – esta chave é comumente usada como uma subchave para criptografar.
Authentication key – esta chave não é utilizada pelo gpg em tudo. Outras ferramentas como módulos PAM ou ssh usam esta chave para serviços de autenticação.
General key info – esse ID de usuário primário é mostrado se a chave pública OpenPGP correspondente está disponível.

Bom, por enquanto é só pessoal! :)

[1] https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html#id2505566

Publicado em Criptografia | Marcado com , | Deixe um comentário

Criptografia: Cifra ou disco de Alberti em Python

Leon Battista Alberti foi um autor, artista, arquiteto, poeta, sacerdote, linguista, filósofo e criptógrafo italiano que descreveu em um tratado (De Componendis Cifris ou De Cifris, 1466), uma técnica criptográfica que fazia uso de dois discos (um fixo e outro móvel) para cifrar e decifrar mensagens.

Como dito, os discos de Alberti são compostos por dois discos: um fixo e outro móvel. No disco fixo fica o alfabeto plano e no disco móvel fica o alfabeto cifrado. Alberti descreve dois métodos para cifragem/decifragem com os discos.

Disco de Alberti

Disco de Alberti

Para melhor exemplificar utilizaremos o disco da imagem acima, onde o disco fixo é o mais externo (com os caracteres maiúsculos) e o disco móvel é o disco interno (com os caracteres minúsculos).

Primeiro Método

Neste primeiro método escolhe-se um caracter do disco móvel que será utilizado como chave, por exemplo, a letra k. A cifragem se dá adicionando-se letras maiúsculas à mensagem a ser cifrada. Quando o usuário encontrar uma letra maiúscula no texto, a chave do disco móvel deve ser movida até que esta fique embaixo da letra maiúscula da mensagem. Agora, as demais letras são cifradas com as letras correspondentes ao disco móvel. Encontrando-se outra letra maiúscula, o disco móvel é deslocado até que a chave k fique abaixo da letra maiúscula no alfabeto plano e continua-se cifrando assim, até a mensagem acabar.

Como exemplo, vamos cifrar a mensagem ‘O sargento é o traidor’. Primeiro, todas as letras maiúsculas são convertidas em minúsculas, os espaços em branco são removidos e os caracteres especiais são trocados. Assim, a mensagem ficará ‘osargentoeotraidor’. Escolhemos a chave, neste caso a letra k, e qual será a letra inicial que será relacionada à chave. Para facilitar, escolhemos a letra B, como mostrado na imagem. Assim, a nossa mensagem deve começar com a letra B, ‘Bosargentoeotraidor’. Se adicionarmos outras letras maiúsculas na mensagem, o disco móvel deverá ser deslocado até que a chave, k, corresponda àquela letra. A mensagem final ficará assim: ‘BosargentoPeoStraidor’. Para cifrar checamos a letra minúscula da mensagem no disco fixo (com letras maiúsculas) e vemos qual é a letra correspondente no disco móvel (letras minúsculas). Abaixo um passo a passo:

Primeira iteração k -> B

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - g k l n p r t v z & x y s o m q i h f d b a c e

texto plano   - B o s a r g e n t o P e o S t r a i d o r
texto cifrado - B y q g m t p x i y P

Segunda iteração k -> P

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - o m q i h f d b a c e g k l n p r t v z & x y s

texto plano   - B o s a r g e n t o P e o S t r a i d o r
texto cifrado - B y q g m t p x i y P h g S

Terceira iteração k -> S

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - x y s o m q i h f d b a c e g k l n p r t v z &

texto plano   - B o s a r g e n t o P e o S t r a i d o r
texto cifrado - B y q g m t p x i y P h g S l g x h o a g

Nossa mensagem cifrada será ByqgmtpxiyPhgSlgxhoag.

Segundo Método

O segundo método muda um pouco, pois ao invés de se usar letras, usam-se os números que existem no disco fixo. Desta vez escolhe-se como chave um caracter do disco fixo como índice e uma letra do alfabeto cifrado para posição inicial. Ao se encontrar um número na mensagem a ser cifrada, a letra do disco móvel correspondente ao número no disco fixo é movida até corresponder com a letra escolhida como índice no disco fixo. E a cifragem continua assim até o fim da mensagem. Vamos utilizar a mesma mensagem do primeiro método: ‘O sargento é o traidor’. Trocamos todos os caracteres maiúsculos por minúsculos, removemos os caracteres em branco e trocamos os caracteres especiais. No final ficamos com a mensagem ‘osargentoeotraidor’.

Escolheremos a letra D no disco fixo como índice e a letra p no disco móvel como caracter inicial de cifragem. Adicionaremos alguns números (entre 1 e 4) e os inseriremos nos locais que desejarmos na mensagem a ser cifrada. A mensagem final será ‘Dosar1gento4eotra2idor’. Abaixo o passo a passo para cifragem:

Primeira iteração p -> D

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - k l n p r t v z & x y s o m q i h f d b a c e g

texto plano   - D o s a r 1 g e n t o 4 e o t r a 2 i d o r
texto cifrado - D s i k q 1

Segunda iteração 1 (a) -> D

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - f d b a c e g k l n p r t v z & x y s o m q i h

texto plano   - D o s a r 1 g e n t o 4 e o t r a 2 i d o r
texto cifrado - D s i k q 1 g c p x r 4

Terceira iteração 4 (h) -> D

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - m q i h f d b a c e g k l n p r t v z & x y s o

texto plano   - D o s a r 1 g e n t o 4 e o t r a 2 i d o r
texto cifrado - D s i k q 1 g c p x r 4 f k t p m 2

Quarta iteração 2 (y) -> D

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - z & x y s o m q i h f d b a c e g k l n p r t v

texto plano   - D o s a r 1 g e n t o 4 e o t r a 2 i d o r
texto cifrado - D s i k q 1 g c p x r 4 f k t p m 2 q y d c

Assim, a mensagem cifrada será Dsikq1gcpxr4fktpm2qydc.

Terceiro Método

Afora os dois métodos citados por Alberti, podemos criar um outro método que utilizaria um sistema de deslocamento automático sem que precisemos inserir outros caracteres na mensagem, bastaria somente escolher a letra inicial do disco fixo, a letra inicial do disco móvel e um número de deslocamento automático. Este número de deslocamento indicaria quantas casas o disco móvel seria deslocado, para a direita ou esquerda, a cada cifragem de um caracter. Para facilitar vamos utilizar uma mensagem menor : ‘perigo’. Escolhemos a letra O do disco fixo, a letra c do disco móvel e o número 2 como chave de deslocamento.

Primeiro caracter (p)

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - y s o m q i h f d b a c e g k l n p r t v z & x

texto plano   - p e r i g o
texto cifrado - e

Segundo caracter (e)

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - & x y s o m q i h f d b a c e g k l n p r t v z

texto plano   - p e r i g o
texto cifrado - e o

Terceiro caracter (r)

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - v z & x y s o m q i h f d b a c e g k l n p r t

texto plano   - p e r i g o
texto cifrado - e o a

Quarto caracter (i)

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - r t v z & x y s o m q i h f d b a c e g k l n p

texto plano   - p e r i g o
texto cifrado - e o a s

Quinto caracter (g)

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - n p r t v z & x y s o m q i h f d b a c e g k l

texto plano   - p e r i g o
texto cifrado - e o a s &

Sexto caracter (o)

DISCOS
FIXO  - A B C D E F G I L M N O P Q R S T V X Z 1 2 3 4
MÓVEL - k l n p r t v z & x y s o m q i h f d b a c e g

texto plano   - p e r i g o
texto cifrado - e o a s & s

A mensagem cifrada será eoas&s.

CÓDIGO

Abaixo o código da classe que implementa os três métodos acima descritos e também com funções que nos permitem adicionar alfabetos personalizados e de tamanho variado, não nos limitando ao alfabeto do disco da imagem no início do post. O código foi salvo no arquivo alberti.py.

class Alberti:
	def shift(self, shift):
		''' (int) -> None
		Desloca o disco movel a quantidade de elementos em shift.
		'''
		shift = -shift
		self.movable_disk = self.movable_disk[shift:] + self.movable_disk[:shift]

	def set_fixed_disk(self, plain_alphabet):
		''' (str) -> None
		Configura o alfabeto do disco fixo com o texto de plain_alphabet.
		'''
		self.fixed_disk = plain_alphabet.upper()

	def set_movable_disk(self, cipher_alphabet):
		''' (str) -> None
		Configura o alfabeto do disco movel com o texto de cipher_alphabet.
		'''
		self.movable_disk = cipher_alphabet.lower()

	def set_keys(self, fixed_key, movable_key):
		''' (char, charstr) -> None
		Configura as chaves do disco fixo e do disco movel;
		Desloca o disco movel de acordo com as chaves.
		'''
		self.set_fixed_key(fixed_key)
		self.set_movable_key(movable_key)
		fixed_id = self.fixed_disk.find(self.fixed_key)
		movable_id = self.movable_disk.find(self.movable_key)
		shift = fixed_id - movable_id
		self.shift(shift)

	def encrypt(self, plaintext, shift = 0, decrypt = False):
		''' (str, [int], [bool]) -> str
		Cifra o plaintext com a cifra de Alberti.
		'''
		ciphertext = ''
		for ch in plaintext:
			if ch.isupper():
				#letra maiuscula
				self.set_keys(ch, self.movable_key)
			elif ch.isdigit():
				#numero
				movable_key = self.movable_disk[self.fixed_disk.find(ch)]
				self.set_keys(self.fixed_key, movable_key)
			else:
				#letra minuscula
				if decrypt:
					#decifrando
					i = self.movable_disk.find(ch)
					ch = self.fixed_disk[i].lower()
				else:
					#cifrando
					i = self.fixed_disk.find(ch.upper())
					ch = self.movable_disk[i]
				if shift:
					#deslocamento
					self.shift(shift)
			ciphertext += ch
		return ciphertext

	def decrypt(self, ciphertext, shift = 0):
		''' (str, [int]) -> str
		Decifra utilizando a cifra de Alberti.
		'''
		#return self.encrypt(ciphertext, shift, True)
		text = ''
		plaintext = self.encrypt(ciphertext, shift, True)
		for ch in plaintext:
			if ch.islower():
				text += ch
		return text

	def set_fixed_key(self, fixed_key):
		''' (char) -> None
		Configura a chave do disco fixo.
		'''
		self.fixed_key = fixed_key.upper()

	def set_movable_key(self, movable_key):
		''' (char) -> None
		Configura a chave do disco movel.
		'''
		self.movable_key = movable_key.lower()

BitBin

TESTES

Desta feita, não vou mostrar o uso da classe, mas vou criar um arquivo de teste e importar a classe Alberti para ele e executar a cifragem/decifragem dos exemplos citados no post. Este código teste foi salvo no arquivo alberti_teste.py e deve ser salvo no mesmo diretório do arquivo alberti.py.

from alberti import Alberti
alb = Alberti()

## PRIMEIRO METODO
##alfabeto do disco fixo
alb.set_fixed_disk('ABCDEFGILMNOPQRSTVXZ1234')
##alfabeto do disco movel
alb.set_movable_disk('gklnprtvz&amp;xysomqihfdbace')
##chave do disco movel
alb.set_movable_key('k')
cifrado = alb.encrypt('BosargentoPeoStraidor')
print 'Cifrando/Decifrando com o primeiro metodo da cifra de Alberti'
print 'Texto cifrado - ' + cifrado
print 'Texto decifrado - ' + alb.decrypt(cifrado)
print ''

## SEGUNDO METODO
##chave inicial do disco movel
alb.set_movable_key('p')
print 'Cifrando/Decifrando com o segundo metodo da cifra de Alberti'
cifrado = alb.encrypt('Dosar1gento4eotra2idor')
print 'Texto cifrado - ' + cifrado
##chave inicial do disco movel
alb.set_movable_key('p')
print 'Texto decifrado - ' + alb.decrypt(cifrado)
print ''

## TERCEIRO METODO
print 'Cifrando/Decifrando com o terceiro metodo'
##chaves do disco fixo e do disco movel
alb.set_keys('O', 'c')
cifrado = alb.encrypt('perigo', 2)
print 'Texto cifrado - ' + cifrado
alb.set_keys('O', 'c')
print 'Texto decifrado - ' + alb.decrypt(cifrado, 2)

O arquivo acima, sendo executado, tem como saída o resultado abaixo:

Cifrando/Decifrando com o primeiro metodo da cifra de Alberti
Texto cifrado - ByqgmtpxiyPhgSlgxhoag
Texto decifrado - osargentoeotraidor

Cifrando/Decifrando com o segundo metodo da cifra de Alberti
Texto cifrado - Dsikq1gcpxr4fktpm2qydc
Texto decifrado - osargentoeotraidor

Cifrando/Decifrando com o terceiro metodo
Texto cifrado - eoas&s
Texto decifrado - perigo

Fontes:
http://en.wikipedia.org/wiki/Alberti_cipher_disk
http://en.wikipedia.org/wiki/Alberti_cipher
http://www.numaboa.com.br/criptografia/historia/158-alberti
http://www.numaboa.com.br/criptografia/127-substituicao-polialfabetica/164-alberti

Publicado em Criptografia | Marcado com , , | 4 Comentários