Cifras criptográficas em repositório no GitHub

Bom, depois de tanto tempo ausente, resolvi postar algo útil :)

Meus últimos posts foram de cifras criptográficas implementadas na linguagem Python. Para facilitar, resolvi disponibilizar os códigos-fontes num repositório no GitHub: https://github.com/fabmedeiros.

Assim, todas as cifras que eu for implementando serão disponibilizadas aqui no blog e lá.

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

Aviso InsecurePlatformWarning ao verificar a lista de pacotes no pip

Hoje fui verificar se havia algum pacote do pip que necessitasse de atualização. Só que ao executar o comando abaixo:

pip list -o

recebi a seguinte mensagem de aviso:

C:\Python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning

De acordo com o link no aviso[1] versões do Python abaixo da 2.7.9 (estou usando a 2.7.8) têm alguma restrição ao módulo ssl e a recomendação é a atualização do Python :) .

Feito a atualização tudo volta ao normal.

[1] https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning

Publicado em Soluções | Marcado com , | Deixe um comentário

Instalando a matplotlib para Python 2.7 no Windows 8.1

Estes dias resolvi criar um gráfico com dados de um arquivo texto. Como gosto de programar em Python, procurei por um módulo/biblioteca que me permitisse a criação destes gráficos o mais simples possível. Encontrei a matplotlib.

Resumindo, a matplotlib é uma biblioteca que permite a criação de gráficos em 2D. Para sua instalação faz-se necessária a utilização da biblioteca NumPy (que é uma biblioteca para computação científica utilizando Python).

Ambas podem ser instaladas pelo pip. Para instalar a matplotlib basta digitar o comando (no prompt):

pip install matplotlib

Só que no final da instalação, recebo o erro abaixo:

error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat
Get it from http://aka.ms/vcpython27

----------------------------------------
Command "C:\Python27\python.exe -c "import setuptools, tokenize;__file__=
\\users\\omega\\appdata\\local\\temp\\pip-build-sk3bzn\\numpy\\setup.py';exec
mpile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'),
file__, 'exec'))" install --record c:\users\omega\appdata\local\temp\pip-judm
record\install-record.txt --single-version-externally-managed --compile" fail
with error code 1 in c:\users\omega\appdata\local\temp\pip-build-sk3bzn\numpy

Pesquisando, descobri que o Python quer compilar a biblioteca NumPy, mas não encontra o compilador para tal (Microsoft Visual C++ 9). Aí entra a Microsoft :)

Ela criou um compilador específico para o Python 2.7 o Microsoft Visual C++ for Python 2.7. No site clicando-se no botão Download, baixamos o arquivo VCForPython27.msi. Após baixado basta rodar o arquivo. O instalador segue o processo padrão de outros instaladores para programas Windows. Após o processo de instalação, digitamos novamente o comando para instalar o matplotlib:

pip install matplotlib

Feito isto, o processo de instalação segue normal.

P.S.: esta mesma dica foi feita num computador rodando Windows 7 64

Publicado em Soluções | Marcado com , , | 1 Comentário

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