Cześć,
Mam problem z dokończeniem zadania w postaci programu, a mianowicie funkcji BFattackSubst tak aby generowała wszystkie możliwe klucze dla danego przedziału. Całość opiera się o Szyfr Nieregularnej transpozycji (https://mattomatti.com/pl/a35ad). Mógłby ktoś nakierunkować jak się za to zabrać i co wymaga poprawy? Ewentualnie jeśli ktoś byłby chętny napisać funkcję odpłatnie to również byłbym zainteresowany. Dziękuje za każdą pomoc i pozdrawiam.
def createKey(key):
dl = len(key)
values = []
for i in range(dl):
values.append(2*int(key[i])+1)
# print(values)
return values
def encrypt(txt, vcode):
txt_dl = len(txt)
dl = 0 # ile liter mieści tabelka
k = 0 # ile kolumn ma tabelka
while dl < txt_dl:
dl += vcode[k % len(vcode)]
k += 1
# print("txt_dl:", txt_dl)
# print("dl:", dl)
# print("k", k)
table = [] # indeksy pierwszych znaków w każdej kolumnie
table.append(0)
for j in range(1, k):
table.append(table[j - 1] + vcode[(j - 1) % len(vcode)])
# print("table:", table)
wynik = []
maxkol = max(vcode)
maxkol = int((maxkol - 1) / 2)
# print("maxkol:", maxkol)
zapis = 0 # ile znakow zostalo zapisane
for j in range(maxkol, -maxkol-1, -1):
# print("J:",j)
for i in range(k):
# print("I:",i)
if((vcode[i % len(vcode)] - 1) / 2 >= abs(j)):
# print("zapis:",zapis)
# print("table[i]:",table[i])
if table[i] >= txt_dl:
wynik.append("_")
else:
wynik.append(txt[table[i]])
zapis += 1
table[i] += 1
return "".join(wynik)
def decrypt(txt, vcode):
txt_dl = len(txt)
dl = 0 # ile liter mieści tabelka
k = 0 # ile kolumn ma tabelka
while (dl < txt_dl):
dl += vcode[k % len(vcode)]
k += 1
# print("txt_dl:", txt_dl)
# print("dl:", dl)
# print("k", k)
maxtab = max(vcode)
table = []
table.append(0)
maxtab = int((maxtab - 1) / 2)
for j in range(maxtab-1, -maxtab-1, -1):
# print("J:", j)
table.append(table[- j + maxtab - 1])
for i in range(k):
if((vcode[i % len(vcode)] - 1) / 2 >= abs(j + 1)):
table[- j + maxtab] += 1
print("TABLE:",table)
wynik = []
zapis = 0
for i in range(k):
for j in range(int(-(vcode[i % len(vcode)] - 1) / 2), int((vcode[i % len(vcode)] - 1) / 2 + 1)):
print("I/J/litera",i,j,txt[table[j + maxtab]])
wynik.append(txt[table[j + maxtab]])
zapis += 1
table[j + maxtab]+=1
return "".join(wynik)
code = '021'
txt = 'TAJNA INFORMACJA'
vcode = createKey(code)
enctxt = encrypt(txt, vcode)
dectxt = decrypt(enctxt, vcode)
print("vcode:", vcode)
print("ENCRYPTED:", enctxt)
print("DECRYPTED:", dectxt)
# zamiast listy ciag znakow
"""
klucz '021'
A R
JI MA
TNNOA_
AF C_
J
ARJIMATNNOA_AFC_ J
dzielniki 18:
1('0'),2('00'),3('1' lub '000'),
6('0100' lub '11' lub '1000' lub '02' lub '20' itp),
9('102' lub '021' lub '0101' itp )
lub (zręczniej w postaci 'vcode'):
1( [1] ), 2( [1,1] ), 3 ( [3] lub [1,1,1] ),
6( [1,3,1,1] lub [3,3] lub [3,1,1,1] lub [1,5] lub [5,1] itp),
9( [3,1,5] lub [1,5,3] lub [1,3,1,3] itp )
"""
"""
Co jeszcze da się zrobić w miarę szybko:
implementować (w rozsądny sposób) atak BruteForcem
z ograniczeniem rozmiaru (ilością komórek) bloku dla szyfrowania (który zadajemy
ciągami cyfr rodzaju '021' lub [1,5,3]) liczbą 10.
Niżej podano przykładową funkcję, generującą wszystkie możliwe klucze
określonego rozmiaru. Z testowania (patrz niżej) wynika, że zaczynając
od rozmiaru bloku 11 BruteForce jest zbyt wolny.
Więc ograniczymy się krótkimi kluczami (dla dłuższych już jest niezbędnym
używanie bardziej zaawansowanych metod, którę już nie zdążycie realizować).
Funkcję 'FindAddons' podaję z tego powodu, że ona zawiera wyłącznie
obliczeniową logikę. A lepiej, jeśli skupicie się na częściach zadania,
bardziej powiązanych z kryptografią.
Co jeszcze pozostało zrobić:
- używając tą funkcję napisać podstawowy 'BruteForce' (sprawdzenie wszystkich
możliwych kluczy, zaczynając od najmniejszego rozmiaru i do 10);
- możliwe rozmiary muszą być dzielnikami długości kryptotekstu;
- w sposób identyczny do przykłądowych
programów ( w plikach w Teams pod numerami 3,4,5,6) dostosować użycie
modułu 'ngram' (i funkcji 'score' z niego) do automatyzowanego sprawdzenia
'czytelności' tekstów, które otrzymujemy po deszyfrowaniu _kryptotekstu_
za pomocą kolejnego klucza. Ta funkcją zwraca ujemne liczby,
czym większa liczba (albo czym mniejsza za modułem) - tym bardziej
prawdopodobne, że otrzymany tekst będzie czytelny. Pliki danych (rodzaju
'english_bigrams.txt' lub 'english_quadgrams.txt') stworzone dla
literackiego angielskiego języka, w którym litery są przekształcone do dużych,
a spację i wszystkie znaki interpunkcyjne są usunięte.
Tzn. tekst(y),
na którym(/których) trzeba testować program, muszą spełniać powyższe warunki.
Pomiędzy innym, to znaczy jeszcze to, że te znaki '_', którę generuję
funkcją deszyfrowania, trzeba usuwać.
"""
from itertools import combinations_with_replacement
from itertools import permutations
import time
import string
import random
import math
from ngram import Ngram_score
# combinations_with_replacement('ABCD', 2)
# n - sum, returns list of possible lists of elements [1,3,5...] with sum = n
def FindAddons( n ):
if n % 2 == 0 :
AddonsNumbers = [ 2*i for i in range( 1, n // 2 +1 ) ]
else:
AddonsNumbers = [ 2*i+1 for i in range( (n+1)//2) ]
lstN = [ 2*i+1 for i in range( (n+1) // 2 ) ]
Addons1 = []
sm = 0
for i in AddonsNumbers :
for j in combinations_with_replacement( lstN, i ):
if sum(j) == n:
Addons1.append( j )
#print(Addons1)
Addons2 = []
for x in Addons1:
for y in permutations(x):
#if y not in Addons2 :
Addons2.append( y )
#print(Addons2)
Addons3 = list( set( Addons2) )
return( [ list( Addons3[i] ) for i in range(len(Addons3)) ] )
def TimeTest():
for n in range(12):
t1 = time.time()
print('n = ', n, ' len(FindAddons(n)) = ', len(FindAddons(n)) )
print('... time elapsed: ', time.time()-t1,' seconds')
return()
"""
n = 0 len(FindAddons(n)) = 0
... time elapsed: 0.05337238311767578 seconds
n = 1 len(FindAddons(n)) = 1
... time elapsed: 0.031244754791259766 seconds
n = 2 len(FindAddons(n)) = 1
... time elapsed: 0.015619993209838867 seconds
n = 3 len(FindAddons(n)) = 2
... time elapsed: 0.015590667724609375 seconds
n = 4 len(FindAddons(n)) = 3
... time elapsed: 0.015619754791259766 seconds
n = 5 len(FindAddons(n)) = 5
... time elapsed: 0.015618324279785156 seconds
n = 6 len(FindAddons(n)) = 8
... time elapsed: 0.015624523162841797 seconds
n = 7 len(FindAddons(n)) = 13
... time elapsed: 0.022132396697998047 seconds
n = 8 len(FindAddons(n)) = 21
... time elapsed: 0.04686403274536133 seconds
n = 9 len(FindAddons(n)) = 34
... time elapsed: 0.2372438907623291 seconds
n = 10 len(FindAddons(n)) = 55
... time elapsed: 1.3357844352722168 seconds
n = 11 len(FindAddons(n)) = 89
... time elapsed: 42.12555551528931 seconds
"""
import string
import random
import time
import math
from ngram import Ngram_score
text = "TAJNA INFORMACJA__"
tj = text.upper().replace(" ", "").replace("_", "").replace("1", "").replace("(", "").replace(")", "").replace(".", "").replace(",","").replace("!", "").replace("?", "").replace("-", "")
alfabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
ns = Ngram_score('english_bigrams.txt')
def BFattackSubst(C):
lista = []
t2 = time.time()
for i in range(26):
t2 = encrypt(C, i)
lista += [[ns.score(t2), t2]]
lista.sort()
lista.reverse()
print ('zatracono: ', time.time()-t1, 'sekund')
return lista[:1]
ct = encrypt(tj, 3)
print(BFattackSubst(ct))