Em 1902, Félix-Marie Delastelle desenvolveu uma nova cifra baseada em sua cifra Bifid, a Trifid. Diferente da Bifid, que usa um quadrado de 5×5, na Trifid são utilizados três quadrados de 3×3 cada.
Utiliza-se o alfabeto completo mais um caracter a escolher (em nosso caso adotamos o sinal positivo (+)), assim, ABCDEFGHIJKLMNOPQRSTUVWXYZ+.
Para não facilitar as coisas, vamos embaralhar o alfabeto acima: ZRBIX+EFAUMDHTWJKYCVSLONPQG.
Preenchemos os três quadrados com os caracteres do alfabeto cifrado:
QUAD 1 QUAD 2 QUAD 3
1 2 3 1 2 3 1 2 3
1 Z | R | B U | M | D C | V | S
2 I | X | + H | T | W L | O | N
3 E | F | A J | K | Y P | Q | G
O princípio de cifragem é similar ao da cifra Bifid. Tomemos, por exemplo, a letra F. Ela está posicionada no QUAD 1, linha 3 e coluna 2, assim, 132 será seu número. Faremos isto para cada letra do texto plano.
Vamos exemplificar com a frase ‘o trem parte às dez’. Desconsiderando-se os espaços e acentos, para cifrar temos:
texto plano - otremparteasdez
quadrado - 3
linha - 2
coluna - 2
Fazendo isto para cada letra obtemos:
texto plano - otremparteasdez
quadrado - 321123112113211
linha - 221313312331131
coluna - 222121322133311
Agora, lemos os números, primeiro dos quadrados, depois das linhas e, por último, das colunas:
321123112113211221313312331131222121322133311
agora separamos de três em três:
321 123 112 113 211 221 313 312 331 131 222 121 322 133 311
Para cada trio de números, procuramos a letra correspondente no quadrado (onde o primeiro número corresponde ao quadrado, o segundo à linha e o terceiro à coluna):
321 123 112 113 211 221 313 312 331 131 222 121 322 133 311
L + R B U H S V P E T I O A C
Assim, o texto inicial cifrado fica: L+RBUHSVPETIOAC
Pode-se usar uma palavra como chave para gerar o alfabeto. Por exemplo, se utilizarmos a palavra chave, geramos um alfabeto assim: CHAVEBDFGIJKLMNOPQRSTUWXYZ+
O mesmo texto plano, cifrado com o novo alfabeto cifrado fica: QEGAARNCIXDMTPE
CÓDIGO
O código faz uso da classe Cipher (que pode ser salva em um arquivo cipher.py) e foi criada a classe Trifid (que pode ser salva no arquivo trifid.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 = self.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
trifid.py
# -*- coding: utf-8 -*-
from cipher import Cipher
class Trifid(Cipher):
def create_alphabet(self, key=''):
alphabet = super().create_alphabet(key) + '+'
return alphabet
def _create_squares(self, alphabet):
square_lines = []
for i in range(0, 9):
square_lines.append(alphabet[0 + 3 * i:3 + 3 * i])
squares = {
"1": square_lines[0:3],
"2": square_lines[3:6],
"3": square_lines[6:9]
}
return squares
def encrypt(self, plaintext, alphabet=''):
quads = ''
lines = ''
cols = ''
ciphertext = ''
plaintext = plaintext.upper()
if alphabet:
square = self._create_squares(alphabet)
else:
square = self._create_squares(self.create_alphabet())
print(square)
### busca letra dentro do tres quadrados
for letra in plaintext:
for quad in square.keys():
for line in square[quad]:
if letra in line:
quads += quad
lines += str(square[quad].index(line) + 1)
cols += str(line.index(letra) + 1)
cipher_num = quads + lines + cols
# varre cipher_num e usa cada tres numeros para varrer os tres quadrados
for i in range(0, len(cipher_num), 3):
idx = cipher_num[i:i + 3]
quad = idx[0]
line = int(idx[1]) - 1
col = int(idx[2]) - 1
ciphertext += square[quad][line][col]
return ciphertext
def decrypt(self, ciphertext, alphabet=''):
text = ciphertext.upper()
cipher_num = ''
if alphabet:
square = self._create_squares(alphabet)
else:
square = self._create_squares(self.create_alphabet())
### busca letra dentro do tres quadrados
for letra in text:
for quad in square.keys():
for line in square[quad]:
if letra in line:
lines = str(square[quad].index(line) + 1)
cols = str(line.index(letra) + 1)
cipher_num += quad + lines + cols
squares = []
for i in range(0, len(cipher_num), len(text)):
squares.append(cipher_num[i:i + len(text)])
plaintext = ''
for col in range(0, len(text)):
item = ''
for lin in range(0, 3):
item += squares[lin][col]
plaintext += square[item[0]][int(item[1]) - 1][int(item[2]) - 1]
return plaintext
TESTE
>>> cifra = Trifid()
>>> alfabeto = 'ZRBIX+EFAUMDHTWJKYCVSLONPQG'
>>> cifrado = cifra.encrypt('otremparteasdez', alfabeto)
>>> print(cifrado)
L+RBUHSVPETIOAC
>>> print(cifra.decrypt(cifrado, alfabeto))
OTREMPARTEASDEZ
>>> alfabeto = cifra.create_alphabet('senha')
>>> cifrado = cifra.encrypt('otremparteasdez', alfabeto)
>>> print(cifrado)
QAFSNRBGHUHPIKL
>>> print(cifra.decrypt(cifrado, alfabeto))
OTREMPARTEASDEZ
FONTES
https://en.wikipedia.org/wiki/Trifid_cipher
http://practicalcryptography.com/ciphers/trifid-cipher/
https://www.dcode.fr/triliteral-cipher