Skip to content

Instantly share code, notes, and snippets.

@rene-d
Created May 10, 2020 08:18
Show Gist options
  • Save rene-d/7dc17857d96ec244528c51a34520af5e to your computer and use it in GitHub Desktop.
Save rene-d/7dc17857d96ec244528c51a34520af5e to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# _ ____ _____ ______ ____ __
# / \ | _ \| ___/ ___\ \ / /\ \/ /
# / _ \ | | | | |_ | | _ \ \ / / \ /
# / ___ \| |_| | _|| |_| | \ V / / \
# /_/ \_\____/|_| \____| \_/ /_/\_\
# rene-d 2020
# références:
# http://www.apprendre-en-ligne.net/crypto/subst/adfgvx.html
# http://www.bibmath.net/crypto/index.php?action=affiche&quoi=debvingt/radiogramme
from operator import itemgetter
import itertools
from textwrap import wrap
import unicodedata
from PyQt5.QtWidgets import (
QApplication,
QPushButton,
QHBoxLayout,
QVBoxLayout,
QPlainTextEdit,
QDialog,
)
import click
import sys
def nettoie_message(s):
chiffres_et_lettres = ["Ll", "Lu", "Nd"]
s_no_accents = "".join(
(c for c in unicodedata.normalize("NFD", s) if unicodedata.category(c) in chiffres_et_lettres)
)
return s_no_accents.lower()
def ioc(message):
n_i = [0] * 26
n = 0
for c in message.upper():
if c.isalpha():
n_i[ord(c) - 65] += 1
n += 1
r = 0
for i in range(26):
r += n_i[i] * (n_i[i] - 1)
r /= n * (n - 1)
return r
def nettoie_cle(cle):
if "," in cle:
cle = map(int, cle.split(","))
# réordonne la clé en commençant à 0
cle = list(
map(
itemgetter(0),
sorted([(i, j[0]) for i, j in enumerate(sorted(enumerate(cle), key=itemgetter(1)))], key=itemgetter(1)),
)
)
return cle
def nettoie_cle_inverse(cle):
cle = nettoie_cle(cle)
inv = [0] * len(cle)
for i, v in enumerate(cle):
inv[v] = i
return inv
def crypte(message, cle="MARCEL", grille="c1ofwjymt5b4i7a28sp30qhxkeul6dvrgzn9"):
cle = nettoie_cle(cle)
nb_colonnes = len(cle)
message = message.replace(" ", "").lower()
grille = grille.lower()
intermediaire = ""
for c in message:
pos = grille.find(c)
intermediaire += "ADFGVX"[pos // 6] + "ADFGVX"[pos % 6]
while len(intermediaire) % nb_colonnes != 0:
intermediaire += "X"
nb_lignes = len(intermediaire) // nb_colonnes
# print(f"\033[2m{cle}\033[0m")
# for i in range(0, len(intermediaire), nb_colonnes):
# print(intermediaire[i : i + nb_colonnes])
# print("nb_colonnes", nb_colonnes)
# print("nb_lignes", nb_lignes)
# print("len", len(intermediaire))
colonnes = [""] * nb_colonnes
for y in range(nb_lignes):
for x in range(nb_colonnes):
colonnes[x] += intermediaire[x + y * nb_colonnes]
final = ""
for x, _ in sorted(enumerate(cle), key=itemgetter(1)):
final += colonnes[x]
print(f"\033[2msecret\033[0m")
print(" ".join(wrap(final, 5)))
return final
def decrypte(message, cle="MARCEL", grille="c1ofwjymt5b4i7a28sp30qhxkeul6dvrgzn9"):
cle = nettoie_cle_inverse(cle)
message = message.replace(" ", "")
matrice_decodage = {}
for pos, c in enumerate(grille):
matrice_decodage["ADFGVX"[pos // 6] + "ADFGVX"[pos % 6]] = c
nb_colonnes = len(cle)
nb_lignes = len(message) // nb_colonnes
# print("nb_colonnes", nb_colonnes)
# print("nb_lignes", nb_lignes)
# print("len", len(message), "=", nb_colonnes * nb_lignes)
colonnes = [""] * nb_colonnes
for x in range(nb_colonnes):
colonnes[x] = message[x * nb_lignes : (x + 1) * nb_lignes]
dest = [""] * nb_colonnes
for i, k in enumerate(cle):
dest[k] = colonnes[i]
intermediaire = ""
for y in range(nb_lignes):
intermediaire += "".join(dest[x][y] for x in range(nb_colonnes))
if len(intermediaire) % 2 == 1:
intermediaire = intermediaire[:-1]
clair = "".join(matrice_decodage[i] for i in wrap(intermediaire, 2))
print(f"\033[2mclair\033[0m")
print(clair)
return clair
def decrypte_test(message, cle, freq_lettres=None):
cle = nettoie_cle_inverse(cle)
if isinstance(freq_lettres, list):
freq_lettres = "".join(freq_lettres)
print(freq_lettres)
message = message.replace(" ", "")
decodage = {}
symboles = []
for pos in range(36):
symbole = "ADFGVX"[pos // 6] + "ADFGVX"[pos % 6]
decodage[symbole] = pos
symboles.append(symbole)
message = message.replace(" ", "")
nb_colonnes = len(cle)
colonnes = [""] * nb_colonnes
nb_lignes = len(message) // nb_colonnes
# print("nb_colonnes", nb_colonnes)
# print("nb_lignes", nb_lignes)
# print("len", len(message), "=", nb_colonnes * nb_lignes)
for x in range(nb_colonnes):
colonnes[x] = message[x * nb_lignes : (x + 1) * nb_lignes]
dest = [""] * nb_colonnes
for i, k in enumerate(cle):
dest[k] = colonnes[i]
# for y in range(nb_lignes):
# print("".join(dest[x][y] for x in range(nb_colonnes)))
intermediaire = ""
for y in range(nb_lignes):
intermediaire += "".join(dest[x][y] for x in range(nb_colonnes))
if len(intermediaire) % 2 == 1:
intermediaire = intermediaire[:-1]
# print(" ".join(wrap(intermediaire, 2)))
# print("".join(decodage[symbole] for symbole in wrap(intermediaire, 2)))
freq = [0] * 36
for symbole in wrap(intermediaire, 2):
pos = decodage[symbole]
freq[pos] += 1
# print(intermediaire)
print(
"".join(
f"{i/(len(intermediaire)/2)*100:.1f} " for _, i in sorted(enumerate(freq), reverse=True, key=itemgetter(1))
)
)
grille = {}
for lettre, pos in enumerate(sorted(enumerate(freq), reverse=True, key=itemgetter(1))):
pos = pos[0]
symbole = "ADFGVX"[pos // 6] + "ADFGVX"[pos % 6]
print(" " + symbole + " ", end="")
grille[symbole] = freq_lettres[lettre]
print()
print("".join(f"{c:>3} " for c in freq_lettres))
texte_grille = "".join(grille[l + c] for l, c in itertools.product("ADFGVX", "ADFGVX"))
print("grille:", texte_grille)
clair = "".join(grille[symbole] for symbole in wrap(intermediaire, 2))
print(clair)
return clair
##############################################################################
@click.group()
def cli():
pass
@cli.command()
def test1():
cle = "MARCEL"
secret = crypte("objectif Arras 15h28", cle)
clair = decrypte(secret, cle)
assert secret == "FDADX VVAGD DGADF FDFXF FFGVA VFXFG DAAXA F".replace(" ", "")
assert clair == "objectif Arras 15h28".replace(" ", "").lower()
@cli.command()
def test2():
# Der „Funkspruch des Sieges“
message = "Munitionierung beschleunigen Punkt soweit nicht eingesehen auch bei Tag"
cle = nettoie_cle_inverse("12, 6, 18, 15, 4, 1, 3, 16, 10, 8, 19, 14, 11, 7, 9, 2, 5, 21, 17, 20, 13")
grille = "c08xf4mk3az9nw1ojd5siyhuplvb6req7t2g"
message_code = "FGAXA XAXFF FAFVA AVDFA GAXFX FAFAG DXGGX AGXFD XGAGX GAXGX AGXVF VXXAG XDDAX GGAAF DGGAF FXGGX XDFAX GXAXV AGXGG DFAGG GXVAX VFXGV FFGGA XDGAX FDVGG A"
secret = crypte(message, cle, grille)
clair = decrypte(message_code, cle, grille)
assert secret == message_code.replace(" ", "")
assert clair == message.replace(" ", "").lower()
class App(QDialog):
def __init__(self, message, cle, freq, parent=None):
super(App, self).__init__(parent)
layout = QHBoxLayout()
self.message = message
self.cle = cle
self.freq = list(freq)
self.swap = None
self.b = []
for i, c in enumerate(self.freq):
b = QPushButton(c, self)
b.setFixedWidth(16)
b.setCheckable(True)
b.setFlat(True)
b.clicked.connect(self.make_callback(i))
layout.addWidget(b)
self.b.append(b)
zz = QVBoxLayout()
zz.addLayout(layout)
self.text = QPlainTextEdit(self)
self.text.setFixedHeight(256)
zz.addWidget(self.text)
self.setLayout(zz)
self.setWindowTitle("Button demo")
self.decrypte()
def make_callback(self, i):
return lambda: self.on_click(i)
def on_click(self, id):
if self.swap is None:
self.swap = id
else:
self.freq[id], self.freq[self.swap] = self.freq[self.swap], self.freq[id]
self.b[self.swap].setChecked(False)
self.b[self.swap].setText(self.freq[self.swap])
self.b[id].setChecked(False)
self.b[id].setText(self.freq[id])
self.setWindowTitle(f"swap {self.swap} et {id}")
self.swap = None
self.decrypte()
def decrypte(self):
clair = decrypte_test(self.message, self.cle, self.freq)
self.text.setPlainText(clair)
if __name__ == "__main__":
cli()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment