Cifra Bifid em Python

Em 1901, o criptógrafo francês, Félix-Marie Delastelle, em seu livro Traité Élémentaire de Cryptographie, descreveu uma cifra criptográfica que mistura o quadrado de Políbio com transposição de colunas. Esta recebeu o nome de Bifid.

Seu princípio de funcionamento começa com um quadrado de Políbio de 5×5 (o J é substituído pelo I). Utilizando-se o alfabeto PLNCYZSMUETBXWVQOAJDKRGFHI temos a tabela abaixo:

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

Vamos exemplificar com a frase ‘o trem parte às dez’. Desconsiderando-se os espaços e acentos, para cifrar procedemos assim: pegamos a linha e a coluna da letra e escrevemos o número abaixo da letra.

texto plano - otremparteasdez
linha       - 4
coluna      - 2

Fazendo isto para cada letra obtemos:

texto plano - otremparteasdez
linha       - 435221453242422
coluna      - 211531311532451

Agora, lemos os números, primeiro das linhas, depois das colunas:

435221453242422211531311532451

agora separamos de dois em dois:

43 52 21 45 32 42 42 22 11 53 13 11 53 24 51

Para cada par de número, procuramos a letra correspondente no quadrado (onde o primeiro número do par corresponde à linha e o segundo, à coluna):

43 52 21 45 32 42 42 22 11 53 13 11 53 24 51
A  G  Z  K  B  O  O  S  P  F  N  P  F  U  R

Assim, o texto inicial cifrado fica: AGZKBOOSPFNPFUR

CÓDIGO

O código faz uso da classe Cipher (que pode ser salva em um arquivo cipher.py) e foi criada a classe Bifid (que pode ser salva no arquivo bifid.py).

cipher.py

# -*- coding: utf-8 -*-
from random import shuffle
""" 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, alphabet = [], 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
        Se key, retorna um square com key iniciando o square
        alphanum square com letras e numeros
        replace letras a serem trocadas, so funciona se for usado somente o alfabeto
        sequence se True continua a preencher o square a partir do ultimo caracter da key
        """
        square = []
        if alphabet:
            if alphanum:
                replace = ['', '']
            # num = 5
            alfabeto = alphabet
        elif alphanum:
            # num = 6
            alfabeto = self.plain_alphanum
            replace = ['', '']
        else:
            # num = 5
            alfabeto = self.plain_alphabet
        alfabeto = self.create_alphabet(key.upper(), alfabeto, replace, sequence)##
        num = 5 + len(alfabeto) % 5
        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_repeated(key)
            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

    def random_alphabet(self, alphanum=False):
        """ Retorna um alfabeto aleatório """
        if alphanum:
            alfabeto = list(self.create_alphabet(alfabeto=self.plain_alphanum))
        else:
            alfabeto = list(self.create_alphabet())
        shuffle(alfabeto)
        return ''.join(alfabeto)

    def key_repeated(self, key):
        ''' Remove caracteres repetidos da senha key '''
        temp = ''
        for ch in key.upper():
            if ch not in temp:
                temp += ch
        return temp

bifid.py

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

class Bifid(Cipher):
    def encrypt(self, plaintext, alphabet=None):
        lins = ''
        cols = ''
        plaintext = plaintext.upper()
        matriz = self.create_square(alphabet)
        for letra in plaintext:
            for lin in matriz:
                if letra in lin:
                    cols += str(lin.find(letra) + 1)
                    lins += str(matriz.index(lin) + 1)
        cipher_num = lins + cols
        ciphertext = ''
        for i in range(0, len(cipher_num), 2):
            ref = cipher_num[i:i + 2]
            ciphertext += matriz[int(ref[0]) - 1][int(ref[1]) - 1]
        return ciphertext

    def decrypt(self, texto, alphabet=None):
        num = ''
        plain = ''
        texto = texto.upper()
        matriz = self.create_square(alphabet)
        for letra in texto:
            for linha in matriz:
                if letra in linha:
                    num += str(matriz.index(linha) + 1) + str(linha.find(letra) + 1)
        linhas = num[:len(num)//2]
        colunas = num[len(num)//2:]
        for i in range(0, len(linhas)):
            plain += matriz[int(linhas[i]) - 1][int(colunas[i]) - 1]
        return plain

TESTE

>>> bifid = Bifid()
>>> cifrado = bifid.encrypt('OTREMPARTEASDEZ', 'PLNCYZSMUETBXWVQOAJDKRGFHI')
>>> print(cifrado)
>>> print(bifid.decrypt(cifrado, 'PLNCYZSMUETBXWVQOAJDKRGFHI'))

Resultado:

AGZKBOOSPFNPFUR
OTREMPARTEASDEZ

FONTES
https://en.wikipedia.org/wiki/Bifid_cipher
http://practicalcryptography.com/ciphers/bifid-cipher/
http://rumkin.com/tools/cipher/bifid.php
https://www.dcode.fr/bifid-cipher

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

Glossário Kindle para a trilogia Ciclo Nessântico

Dando prosseguimento em minhas leituras, em 2016 comecei a ler uma outra série de livros de fantasia, a trilogia Ciclo Nessântico, cujo primeiro volume é O Trono do Sol – A Magia da Alvorada.

Dei início ao segundo volume neste mês e fiz, como a série a Roda do Tempo, um glossário para quem deseja ler o livro em um Kindle.

Desde já aviso que o glossário cobre somente o primeiro volume da trilogia e pode conter alguns spoilers sobre personagens ou situações do livro.

Conforme eu termine a leitura dos outros títulos, o glossário será expandido e atualizado.

Para baixar clique aqui.

[ATUALIZAÇÃO 21/11/2018]

Li os dois outros livros da trilogia (O Trono do Sol – A Magia do Anoitecer e O Trono do Sol – A Magia da Aurora) e terminei a edição do glossário, que agora contempla os termos para os três livros (lembre-se que o glossário pode conter alguns spoilers dos livros).

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

Assinando documentos no LibreOffice com GnuPG no Windows

Há algum tempo, o LibreOffice recebeu o suporte de assinar documentos com o GnuPG em sua versão para Linux. E, agora, com o lançamento da versão 6, esta opção também está disponível para a versão do LibreOffice para Windows.

Antes de tudo deve-se ter o GnuPG instalado. Para Windows instalamos o GnuPG utilizando o gpg4win (versão atual 3.1.0, que já vem com o GnuPG 2.2.6).

Se você já o instalou, mas não tem uma chave criada, vamos criar uma usando o Kleopatra. Execute-o em Iniciar->Programas->Kleopatra.

Uma janela como a abaixo se abrirá

Clique em Novo Par de Chaves, e, na tela que aparecer, preencha seu nome e seu e-mail (como vou criar as chaves, apenas para demonstração, preenchi com seu nome e seuemail@seuemail.com 🙂 e não alterei nada no botão Configurações avançadas).

Clicando em Next, somos levados a uma tela que mostra as nossas informações e podemos clicar em Criar

Rapidamente, se abrirá uma tela como abaixo, onde somos levados a criar uma senha para as nossas chaves

Caso a senha criada, seja menor que 8 caracteres e não contenha pelo menos um número ou caracter especial, aparecerá a janela abaixo

E, finalmente, após algum tempo, aparecerá a tela abaixo, confirmando a criação do nosso par de chaves.

Agora, vamos à assinatura do documento usando o LibreOffice. Execute o LibreOffice, crie um novo documento e depois clique em Arquivo -> Assinaturas Digitais -> Assinaturas Digitais. Se o arquivo não estiver salvo, será solicitado que isto seja feito.

Na janela que se abre clique em Assinar documento…

Observe que o certificado criado aparece. Clique agora em Assinar

Digite a senha que você criou para as chaves

E pronto.

Clique em Fechar. Documento assinado.

Lembre-se que se você alterar o documento, aparecerá a mensagem abaixo

E se você o salvar, a assinatura será removida e o documento deve ser assinado novamente.

OpenPGP signature support in LibreOffice
How to digitally sign a LibreOffice 6 document with GnuPG

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

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

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 , , , , | 1 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