Criptografia: cifra ADFGVX em Python

A cifra ADFGVX foi uma evolução da cifra ADFGX, utilizada pelo exército alemão como uma cifra mais segura.

A adição de mais uma letra (V) permitiu-se o uso de um alfabeto de 26 letras mais os dez dígitos numéricos.

Seu funcionamento é o mesmo da cifra ADFGX com o diferencial de se usar agora uma tabela de 6×6 caracteres.

Os dois passos para a cifram são: 1) distribuir o alfabeto cifrado no quadrado de 6×6; 2) tabela de transposição com um índice de coluna determinado por uma senha.

Escolhemos o alfabeto cifrado ZC1BD5MH9AO6INL2RSPQ7WX0EU3JTY8FGK4V.

  A|D|F|G|V|X
A|Z|C|1|B|D|5
D|M|H|9|A|O|6
F|I|N|L|2|R|S
G|P|Q|7|W|X|0
V|E|U|3|J|T|Y
X|8|F|G|K|4|V

Para cifrarmos um texto, procuramos a letra do texto a ser cifrado, identificando a linha e a coluna e copiamos seus respectivos índices. Por exemplo, a letra A cifrada ficará como DG. Vamos cifrar a frase ‘reuniao as 10h’.

O texto da primeira etapa fica assim: FV VA VD FD FA DG DV DG FX AF GX DD

A segunda parte da cifram consiste no uso de uma senha de até 26 caracteres, não repetidos. Para cada letra será criada uma coluna e as linhas serão compostas pelo texto cifrado resultante do primeiro passo. O preenchimento se dá da primeira coluna até chegar a última, e se ainda restarem caracteres, uma nova linha é criada. O processo segue até o último caractere. Vamos usar, como exemplo, a senha CHAVE:

C|H|A|V|E
F|V|V|A|V
D|F|D|F|A
D|G|D|V|D
G|F|X|A|F
G|X|D|D|

Terminado o preenchimento, vem a parte da transposição das colunas. Neste caso as colunas e seus conteúdos, são transpostos para que as letras fiquem em sentido crescente do alfabeto. Sendo assim:

A|C|E|H|V
V|F|V|V|A
D|D|A|F|F
D|D|D|G|V
X|G|F|F|A
D|G| |X|D

Agora, para formamos o texto cifrado final, basta que efetuemos a leitura de cada coluna, de cima para baixo. Assim, o texto ‘reuniao as 10h’, cifrado, ficará:

VDDXDFDDGGVADFVFGFXAFVAD

CÓDIGO

O código foi salvo no arquivo adfgvx.py.

# -*- coding: utf-8 -*-

from adfgx import ADFGX
from cipher import Cipher

class ADFGVX(ADFGX):
    def __init__(self):
        self.chars = {
            'A': 0, 'D': 1, 'F': 2,
            'G': 3, 'V': 4, 'X': 5
        }
        self.replace = ()

    def create_square(self, alphabet):
        self.square = Cipher.create_square(self, alphabet=alphabet, alphanum=True)

Note que a classe ADFGVX importa a classe ADFGX, mas altera o dicionário chars para utilizar a nova letra (V).

TESTE

from ciphers import ADFGVX

cifra = ADFGVX()
alfabeto = 'ZC1BD5MH9AO6INL2RSPQ7WX0EU3JTY8FGK4V'
cifra.create_square(alfabeto)
cifrado = cifra.encrypt('reuniao as 10h', 'chave')
print('Texto cifrado: ' + cifrado)
print('Texto decfrado: ' + cifra.decrypt(cifrado, 'chave'))

Resultado:

Texto cifrado: VDDXDFDDGGVADFVFGFXAFVAD
Texto decfrado: REUNIAOAS10H

Fontes:
https://en.wikipedia.org/wiki/ADFGVX_cipher
http://practicalcryptography.com/ciphers/adfgvx-cipher/
http://crypto.interactive-maths.com/adfgvx-cipher.html

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

Criptografia: Cifra ADFGX em Python

Em 1918, durante a Primeira Guerra Mundial, o coronel alemão Fritz Nebel, oficial de inteligência, desenvolveu um cifra criptográfica, utilizada pela primeira vez em 5 de março de 1918.

Uma combinação de vários métodos (tais como o quadrado de Políbio com uma transposição de colunas) resultou na cifra ADFGX.

Como o quadrado de Políbio, a cifra utiliza um quadrado de 5×5, onde cada coluna e cada linha é identificada por uma letra (A, D, F, G, X).

A cifragem ADFGX tem dois passos: o primeiro consiste em distribuir o alfabeto cifrado no quadrado de 5×5 e o segundo passo consiste numa tabela de transposição com um índice de coluna determinado por uma senha.

Escolhemos um alfabeto de 25 letras (neste caso, o J será substituído pelo I) e o distribuímos no quadrado criado. Escolhemos o alfabeto cifrado ZCBDMHAOINLRSPQWXEUTYFGKV.

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

Para cifrarmos um texto, procuramos a letra do texto a ser cifrado, identificando a linha e a coluna e copiamos seus respectivos índices. Por exemplo, a letra A cifrada ficará como DD. Vamos cifrar a frase ‘guerra mundial’. Lembre-se que se o texto contiver o J, este deve ser cifrado como I.

O texto da primeira etapa fica assim: XF GG GF FD FD DD AX GG DX AG DG DD FA

A segunda parte da cifram consiste no uso de uma senha de até 26 caracteres, não repetidos. Para cada letra será criada uma coluna e as linhas serão compostas pelo texto cifrado resultante do primeiro passo. O preenchimento se dá da primeira coluna até chegar a última, e se ainda restarem caracteres, uma nova linha é criada. O processo segue até o último caractere. Vamos usar, como exemplo, a senha CHAVE:

C|H|A|V|E
X|F|G|G|G
F|F|D|F|D
D|D|A|X|G
G|D|X|A|G
D|G|D|D|F
A| | | |

Terminado o preenchimento, vem a parte da transposição das colunas. Neste caso as colunas e seus conteúdos, são transpostos para que as letras fiquem em sentido crescente do alfabeto. Sendo assim:

A|C|E|H|V
G|X|G|F|G
D|F|D|F|F
A|D|G|D|X
X|G|G|D|A
D|D|F|G|D
 |A| | |

Agora, para formamos o texto cifrado final, basta que efetuemos a leitura de cada coluna, de cima para baixo. Assim, o texto ‘guerra mundial’, cifrado, ficará:

GDAXDXFDGDAGDGGFFFDDGGFXAD

CÓDIGO

O código foi salvo no arquivo adfgx.py.

# -*- coding: utf-8 -*-
""" Cifra ADFGX """
from cipher import Cipher

class ADFGX(Cipher):
    """ Cifra ADFGX """
    def __init__(self):
        self.chars = {
            'A': 0, 'D': 1, 'F': 2,
            'G': 3, 'X': 4
        }
        self.replace = ()

    def create_square(self, alphabet):
        """ Cria o quadrado para o alfabeto cifrado """
        self.square = Cipher.create_square(self, alphabet=alphabet)

    def get_adfgx(self, col, lin):
        """ Com as coordenadas, retorna o par de letras ADFGX correspondente """
        out = ''
        for char, value in self.chars.items():
            if col == value:
                out = char + out
            if lin == value:
                out += char
        return out

    def get_letter(self, ch):
        """ Com um par ADFGX, retorna uma letra do quadrado """
        i = self.chars[ch[0]]
        j = self.chars[ch[1]]
        return self.square[i][j]

    def set_replace(self, ch1, ch2):
        """ Substitui ch1 por ch2 """
        self.replace = (ch1, ch2)

    def encrypt(self, text, key):
        """ Cifra o texto com a cifra ADFGX """
        text = self.format_str(text)
        if self.replace:
            if self.replace[0] in text:
                text = text.replace(self.replace[0], self.replace[1])
        txt = []
        for letra in text:
            for col, text in enumerate(self.square):
                if letra in text:
                    lin = text.index(letra)
                    txt.append(self.get_adfgx(col, lin))
        ctxt = {}
        idx = 0
        for ch in ''.join(txt):
            if ctxt.get(key[idx]):
                ctxt[key[idx]] = ctxt.get(key[idx]) + ch
            else:
                ctxt[key[idx]] = ch
            if idx < len(key) - 1:
                idx += 1
            else:
                idx = 0
        ciphertext = ''
        for ch in sorted(ctxt):
            ciphertext += ctxt[ch]
        return ciphertext

    def decrypt(self, text, key):
        """ Decifra texto cifrado com a cifra ADFGX """
        extra = ''
        tam = len(text) % len(key)
        if tam:
            extra = key[:tam]
        fix = len(text) // len(key)
        okey = sorted(key)
        ptxt = {}
        idx = 0
        ext = 0
        for ch in okey:
            if ch in extra:
                ext = 1
            else:
                ext = 0
            ptxt[ch] = text[idx:idx + fix + ext]
            idx += fix + ext
        adfgx = ''
        for i in range(len(ptxt[key[0]])):
            for ch in key:
                if i < len(ptxt[ch]):
                    adfgx += ptxt[ch][i]
        plain = ''
        for _ in range(0, len(adfgx), 2):
            plain += self.get_letter(adfgx[_:_+2])
        return plain

TESTE

from ciphers import ADFGX

cifra = ADFGX()
cifra.create_square('ZCBDMHAOINLRSPQWXEUTYFGKV')
cifrado = cifra.encrypt('guerra mundial', 'chave')
print('Texto cifrado: ' + cifrado)
print('Texto decfrado: ' + cifra.decrypt(cifrado, 'chave'))

Resultado:

Texto cifrado: GDAXDXFDGDAGDGGFFFDDGGFXAD
Texto decfrado: GUERRAMUNDIAL

Fontes:
https://en.wikipedia.org/wiki/ADFGVX_cipher
http://practicalcryptography.com/ciphers/adfgx-cipher/
http://crypto.interactive-maths.com/adfgvx-cipher.html

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

Glossário Kindle para série A Roda do Tempo

Em 2015, li o primeiro livro da série A Roda do Tempo, O Olho do Mundo.

Li-o no Kindle Paperwhite e, apesar do livro possuir um glossário em seu final, não era muito prático ficar navegando da página em que eu estava lendo e ir até o final do livro para consultar um termo ou personagem.

Assim, mesmo tendo passado tanto tempo, resolvi criar um glossário para o Kindle, a ser instalado e utilizado como um dicionário comum do Kindle (pensando na leitura que farei dos próximos volumes).

No momento o glossário só abrange o primeiro livro da série. De acordo em que eu for lendo os outros livros, este glossário receberá os termos adicionais.

Para baixar clique aqui.

[ATUALIZAÇÃO 20/06/2017]

O glossário agora está atualizado com os termos do segundo livro, A Grande Caçada.

Um aviso, o glossário contêm spoilers sobre a situação de alguns personagens.

 

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

Correções nos módulos da ACF2007 para o The SWORD Project

Atendendo à uma solicitação do pessoal do The SWORD Project, fiz duas correções nos módulos da ACF2007 que poderiam travar ou impedir alguns aplicativos de acessar o módulo.

Os downloads estão disponíveis no box.com ou pela página de livros digitais.

[ATUALIZAÇÃO 06/08/2017]

Conforme relatado pelo leitor Carlos, ele estava tendo um problema no módulo da ACF rodando no Xiphos do Linux. Após verificar, descobri que o módulo apresentava este erro, pois não estava usando a codificação UTF-8. Alterado isto, o módulo funcionou perfeitamente. Assim, se você está tendo o mesmo problema, atualize seu módulo da ACF 2007 (versão 1.0.1).

Publicado em Bíblia | Marcado com , | Deixe um comentário

Bíblia ACF 2007 com subtítulos (ePub, mobi)

Atendendo ao pedido do LoiltonJC, consegui converter para ePub e mobi a Bíblia ACF 2007 com subtítulos entre os versículos. Os subtítulos servem como pequenos resumos do que será tratado nos versículos que o seguem.

Para exemplificar, observe a imagem abaixo. A imagem da esquerda é a versão da Bíblia sem os subtítulos e a da direita com eles.

telas

Como de costume, o download está disponível no box.com ou pela página de livros digitais. Os arquivos com esta opção são ACF2007-sub.epub e ACF2007-sub.mobi.

 

Publicado em Bíblia | Marcado com , , | 1 Comentário

Criptografia: Cifra Playfair em Python

A cifra Playfair, também conhecida como quadrado de Playfair, foi uma cifra inventada por Charles Wheastone em 1854, mas que recebeu seu nome por causa de Lyon Playfair ou Lorde Playfair, que conseguiu que fosse utilizada pelo governo britânico. É uma cifra de substituição e cuja técnica principal consiste no uso de digramas ou bigramas (um par de letras) no processo de cifragem/decifragem.

Seu princípio de funcionamento usa uma tabela 5×5 preenchida com as 26 letras do alfabeto latino (como a tabela é um quadrado de 5×5, resultando em 25 células, optamos por unir as letras i e j numa mesma célula, onde todo j na mensagem a ser cifrada será substituído por i) e uma palavra-chave ou senha.

Usando como senha a palavra ESPIAO, preenchemos a tabela como mostrado abaixo:

   1 2 3 4 5
1 |E|S|P|I|A|
2 |O|B|C|D|F|
3 |G|H|K|L|M|
4 |N|Q|R|T|U|
5 |V|W|X|Y|Z|

A primeira etapa da cifragem consiste na divisão da mensagem em digramas (pares de letras). Assim, a frase temos um agente infiltrado, ficará assim:

te mo su ma ge nt ei nf il tr ad ow

Quando dividimos a frase em digramas, vemos que a última letra da frase ficou sozinha. Assim, adicionamos uma letra (adotarei o w) a ela para formar o par.

A segunda etapa é pegarmos cada par de letras e as localizarmos na tabela.

Há três regras para cifrar um par de letras.

1) se as letras estão na mesma linha, cada letra é trocada pela letra da coluna da direita; caso a letra esteja no final da linha troca-se pela primeira letra da mesma linha. Exemplo, o par nt (n linha 4 e coluna 1, t linha 4 e coluna 4 – em vermelho) é trocado por QU (Q linha 4 e coluna 2, U linha 4 e coluna 5 – em verde);

   1 2 3 4 5
1 |E|S|P|I|A|
2 |O|B|C|D|F|
3 |G|H|K|L|M|
4 |N|Q|R|T|U|
5 |V|W|X|Y|Z|

2) se as letras estão na mesma coluna, cada letra é trocada pela letra da linha logo abaixo; caso a letra esteja no final da coluna, troca-se a letra pela letra do início da mesma coluna. Exemplo, o par il (i L1 C4, l L3 C4) é trocado por DT (D L2 C4, T L4 C4);

   1 2 3 4 5
1 |E|S|P|I|A|
2 |O|B|C|D|F|
3 |G|H|K|L|M|
4 |N|Q|R|T|U|
5 |V|W|X|Y|Z|

3) já, se as letras estiverem em linhas e colunas diferentes, a troca se dará assim: a primeira letra será trocada pela letra que estiver na mesma linha da primeira letra e na coluna da segunda letra; a segunda letra será trocada pela letra que estiver na mesma linha da segunda letra e na coluna da primeira letra. Exemplo, o par ow (o L2 C1, w L5 C2) é trocado por BV (B L2 C2, V L5 C1).

   1 2 3 4 5
1 |E|S|P|I|A|
2 |O|B|C|D|F|
3 |G|H|K|L|M|
4 |N|Q|R|T|U|
5 |V|W|X|Y|Z|

Assim, nossa mensagem cifrada ficará assim:

NIGFAQUFNOQUSAUODTUTIFBV

Vale uma observação. Pode ocorrer o caso quando dividimos a frase em digramas, de um ou mais digramas ficarem com letras iguais. Neste caso, o digrama será separado e acrescentada uma letra entre eles (no meu caso, resolvi adicionar a letra w).

Por exemplo, a frase nossa esperança é a sua vinda, os digramas ficariam assim:

no ss ae sp er an ca ea su av in da

Como há o digrama ss, acrescentamos o w entre eles e nossa frase ficará assim:

no sw sa es pe ra nc ae as ua vi nd aw

E o texto cifrado:

NIGFAQUFNOQUSAUODTUTIFBV

CÓDIGO

O código foi salvo no arquivo playfair.py e precisa do arquivo cipher.py (que está abaixo e é utilizada em alguns outras cifras publicadas no blog).

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

class Playfair(Cipher):
    def encrypt(self, text, key = '', decrypt = False):
        """Retorna text cifrado com a cifra de Playfair.
        key - chave a ser usada; havendo chave, o alfabeto sera iniciado com ela
        decrypt - se True, decifra; se False, cifra
        """
        ciphertext = ''
        text = text.upper()
        text = text.replace('J', 'I').replace(' ', '')
        # checa se o texto contem par de letras iguais
        text = self.check_double(text)
        # se text nao tiver numero par de letras
        if len(text) % 2:
            text += 'W'
        # cria a tabela
        self.square = self.create_square(key)
        for i in range(0, len(text), 2):
             ciphertext += self.change_pair(text[i:i + 2], decrypt)
        return ciphertext.upper()

    def decrypt(self, ciphertext, key = ''):
        """Retorna o ciphertext decifrado com a cifra de Playfair"""
        return self.encrypt(ciphertext.upper(), key, True).lower()

    def check_double(self, text):
        out = ''
        for idx in range(0, len(text), 2):
            pair = text[idx:idx+2]
            if len(pair) > 1 and pair[0] == pair[1]:
                out += pair[0] + 'W' + pair[1]
            else:
                out += pair
        return out

    def change_pair(self, pair, decrypt = False):
        """Retorna as posicoes de um par de letras de uma matriz 5x5."""
        # retorno - valor a ser retornado quando se atinge o limite da tabela
        # limite - valor de limite das celulas da tabela
        # passo - valor de incremento/decremento
        if decrypt:
            retorno = 4
            limite = -1
            passo = -1
        else:
            retorno = 0
            limite = 5
            passo = 1
        coord1, coord2 = self.coords(pair)
        if coord1[0] == coord2[0]:
            # caso em que as duas letras estao na mesma linha
            coord1[1] += passo
            coord2[1] += passo
        elif coord1[1] == coord2[1]:
            # caso em que as duas letras estao na mesma coluna
            coord1[0] += passo
            coord2[0] += passo
        else:
            # caso em que as duas letras nao estao na mesma linha nem mesma coluna
            coord1[1], coord2[1] = coord2[1], coord1[1]
        coord1 = [retorno if x == limite else x for x in coord1]
        coord2 = [retorno if x == limite else x for x in coord2]
        return self.letter(coord1) + self.letter(coord2)

    def coords(self, pair):
        """Retorna as coordenadas de um par de letras numa matriz."""
        coords = []
        for letter in pair:
            for line in range(len(self.square)):
                if letter in self.square[line]:
                    coords.append([line, self.square[line].index(letter)])
                    break
        return coords

    def letter(self, coord):
        """Retorna a letra com a coordenada dada"""
        return self.square[coord[0]][coord[1]]

cipher.py

# -*- coding: utf-8 -*-
""" Classe com metodos basicos para cifras classicas """

class Cipher(object):
    """ Classe base para as cifras classicas """
    plain_alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    plain_alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

    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]

    def create_square(self, key = '', alphanum = False, replace = ['J', 'I'], sequence = False):
        """Retorna um alfabeto numa matriz de num x num
        Por padrao, retorna uma matriz formada pelo alfabeto ABCDEFGHIKLMNOPQRSTUVWXYZ
        """
        square = []
        if alphanum:
            num = 6
            alfabeto = self.plain_alphanum
            replace = ['', '']
        else:
            num = 5
            alfabeto = self.plain_alphabet
        alfabeto = self.create_alphabet(key, alfabeto, replace, sequence)
        for idx in range(0, len(alfabeto), num):
            square.append(alfabeto[idx:idx + num])
        return square

    def create_alphabet(self, key = '', alfabeto = plain_alphabet, replace = ['', ''], sequence = False):
        '''Retorna um alfabeto com key como chave e no inicio do alfabeto'''
        if key:
            key = key.upper()
            temp = ''
            for ch in key:
                if ch not in temp:
                    temp += ch
            key = temp
            if replace[0] in key:
                key = key.replace(replace[0], replace[1])
            if sequence:
                idx = alfabeto.index(key[-1])
                alfabeto = self.shift_alphabet(alfabeto, idx)
        cipher = alfabeto.replace(replace[0], '')
        for ch_key in key:
            if ch_key in cipher:
                cipher = cipher.replace(ch_key, '')
        return key + cipher

Estas cifras, bem como todas as outras estão disponíveis em meu GitHub.

TESTES

from playfair import Playfair

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 = Playfair()
cifrado = cifra.encrypt(txt_in, password)
print(cifrado)
print(cifra.decrypt(cifrado, password))

Cujo resultado de saída será:

Texto a ser cifrado: temos um agente infiltrado
Senha: espiao
NIGFAQUFNOQUSAUODTUTIFBV
temosumagenteinfiltradow
Fontes:
http://www.numaboa.com.br/criptografia/substituicoes/poligramicas/1041-playfair
https://en.wikipedia.org/wiki/Playfair_cipher
http://practicalcryptography.com/ciphers/playfair-cipher/
https://learncryptography.com/classical-encryption/playfair-cipher
http://crypto.interactive-maths.com/playfair-cipher.html
Publicado em Criptografia | Marcado com , | 2 Comentários

Como exportar as notas de documentos pessoais no Kindle para iPad

Então, você está lendo aquele documento pessoal no Kindle para iPad e fez várias anotações nele. Agora, por um motivo qualquer você quer exportar estas notas. Mas como fazer?

No Kindle para iPad há uma opção que permite exportar estas notas enviado-as por email. Para fazer basta proceder assim.

Com o livro aberto (para este exemplo vamos utilizar a Bíblia ACF 2007, disponível aqui),

image00

clique no ícone de anotações (canto superior direito).

image01

Ao abrir a tela do Meu caderno de anotações, clique no ícone de exportar (canto superior direito),

image02

selecione E-mail.

image03

Escolha um estilo (eu optei por Nenhum) e clique em Exportar.

image04

Digite o endereço de email para o qual quer enviar o arquivo exportado em formato HTML e clique em Enviar.

image05

Abaixo, como fica o HTML do arquivo exportado.

nota

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