From 5da2af5163b6806a5fa371dddf79af19e5020e77 Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 9 Jul 2021 13:52:44 +0200 Subject: [PATCH 01/33] Update Readme --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index a163703..9c8e469 100644 --- a/README.rst +++ b/README.rst @@ -33,7 +33,7 @@ SecretPy is a cryptographic Python package. It uses the following classical ciph - Rot13, Rot5, Rot18, Rot47 - Scytale - Simple Substitution -- Transposition +- Transposition - Columnar, Myszkowski, Zigzag(Railfence) - Vic - Vigenere, Autokey, Gronsfeld, Porta @@ -110,7 +110,7 @@ The cipher classes can encrypt only characters which exist in the alphabet, and CryptMachine ------------ -``CryptMachine`` saves a state. There are alphabet, key and cipher, they can be changed in anytime. +``CryptMachine`` saves a state. There are alphabet, key and cipher, they can be changed at anytime. In the previous example, plaintext contains only characters existing in the alphabet i.e. without spaces and etc. To change the behaviour, you can use ``CryptMachine`` and decorators(``SaveAll``, ``Block``), so it's a preferred way to do encryption/decryption: @@ -128,6 +128,8 @@ To change the behaviour, you can use ``CryptMachine`` and decorators(``SaveAll`` print(machine.decrypt(enc)) + key = 3 + cipher = Caesar() cm0 = CryptMachine(cipher, key) cm = cm0 From fecfbbd6cd6afcdaf8c827de01f59d9202a811f8 Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 9 Jul 2021 15:38:37 +0200 Subject: [PATCH 02/33] Remove redundant decorators --- examples/atbash.py | 6 ++--- examples/bazeries.py | 8 +++---- examples/chao.py | 4 ++-- examples/polybius.py | 8 +++---- examples/rot18.py | 8 +++---- examples/rot47.py | 9 ++++--- examples/three_square.py | 8 +++---- secretpy/cmdecorators/__init__.py | 7 +----- secretpy/cmdecorators/lowercase.py | 13 ---------- secretpy/cmdecorators/nospaces.py | 18 -------------- secretpy/cmdecorators/remove_non_alphabet.py | 23 ------------------ secretpy/cmdecorators/savespaces.py | 25 -------------------- secretpy/cryptmachine.py | 2 -- 13 files changed, 21 insertions(+), 118 deletions(-) delete mode 100755 secretpy/cmdecorators/lowercase.py delete mode 100755 secretpy/cmdecorators/nospaces.py delete mode 100755 secretpy/cmdecorators/remove_non_alphabet.py delete mode 100755 secretpy/cmdecorators/savespaces.py diff --git a/examples/atbash.py b/examples/atbash.py index 96673cb..15f762f 100755 --- a/examples/atbash.py +++ b/examples/atbash.py @@ -1,9 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Atbash -from secretpy import CryptMachine -from secretpy import alphabets +from secretpy import Atbash, CryptMachine, alphabets import secretpy.cmdecorators as md @@ -17,7 +15,7 @@ def encdec(machine, plaintext): cm = CryptMachine(Atbash()) -cm = md.NoSpaces(md.UpperCase(cm)) +cm = md.UpperCase(cm) plaintext = u"attackatdawn" encdec(cm, plaintext) diff --git a/examples/bazeries.py b/examples/bazeries.py index bc3a86f..c2385ba 100755 --- a/examples/bazeries.py +++ b/examples/bazeries.py @@ -1,10 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Bazeries -from secretpy import CryptMachine -from secretpy import alphabets -from secretpy.cmdecorators import NoSpaces, UpperCase +from secretpy import Bazeries, CryptMachine, alphabets +from secretpy.cmdecorators import UpperCase def encdec(machine, plaintext): @@ -20,7 +18,7 @@ def encdec(machine, plaintext): key = (81257, u"eightyonethousandtwohundredfiftyseven") -cm = NoSpaces(UpperCase(CryptMachine(Bazeries()))) +cm = UpperCase(CryptMachine(Bazeries())) cm.set_alphabet(alphabet) cm.set_key(key) diff --git a/examples/chao.py b/examples/chao.py index f57e2a3..112c756 100755 --- a/examples/chao.py +++ b/examples/chao.py @@ -2,7 +2,7 @@ # -*- encoding: utf-8 -*- from secretpy import Chao, CryptMachine, alphabets -from secretpy.cmdecorators import UpperCase, SaveSpaces +from secretpy.cmdecorators import UpperCase, SaveAll def encdec(machine, plaintext): @@ -16,7 +16,7 @@ def encdec(machine, plaintext): alphabet = "ptlnbqdeoysfavzkgjrihwxumc" # RIGHT WHEEL PT key = "hxuczvamdslkpefjrigtwobnyq" # LEFT WHEEL CT -cm = SaveSpaces(UpperCase(CryptMachine(Chao(), key))) +cm = UpperCase(SaveAll(CryptMachine(Chao(), key))) cm.set_alphabet(alphabet) plaintext = "well done is better than well said" diff --git a/examples/polybius.py b/examples/polybius.py index 35caaf5..f6b9e4f 100755 --- a/examples/polybius.py +++ b/examples/polybius.py @@ -1,9 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Polybius, CryptMachine -from secretpy.cmdecorators import LowerCase -import secretpy.alphabets as alph +from secretpy import Polybius, CryptMachine, alphabets as alph +from secretpy.cmdecorators import SaveAll def encdec(machine, plaintext): @@ -15,7 +14,7 @@ def encdec(machine, plaintext): print("----------------------------------") -cm = CryptMachine(Polybius()) +cm = SaveAll(CryptMachine(Polybius())) plaintext = u"defendtheeastwallofthecastle" encdec(cm, plaintext) @@ -36,5 +35,4 @@ def encdec(machine, plaintext): cm.set_alphabet(alph.GREEK) plaintext = u"ΠΙΝΑΚΑΣ" -cm = LowerCase(cm) encdec(cm, plaintext) diff --git a/examples/rot18.py b/examples/rot18.py index f79a4a5..cbbb700 100755 --- a/examples/rot18.py +++ b/examples/rot18.py @@ -1,10 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Rot18 -from secretpy import CryptMachine -from secretpy.cmdecorators import SaveCase, SaveSpaces, UpperCase -from secretpy import alphabets +from secretpy import Rot18, CryptMachine, alphabets +from secretpy.cmdecorators import SaveAll, UpperCase def encdec(machine, plaintext): @@ -16,7 +14,7 @@ def encdec(machine, plaintext): print(dec) -cm = SaveCase(SaveSpaces(CryptMachine(Rot18()))) +cm = SaveAll(CryptMachine(Rot18())) plaintext = u"The man has 536 dogs" encdec(cm, plaintext) diff --git a/examples/rot47.py b/examples/rot47.py index cdf19f5..d41c8c6 100755 --- a/examples/rot47.py +++ b/examples/rot47.py @@ -1,9 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Rot47 -from secretpy import CryptMachine -from secretpy.cmdecorators import SaveSpaces +from secretpy import Rot47, CryptMachine +from secretpy.cmdecorators import SaveAll def encdec(machine, plaintext): @@ -15,7 +14,7 @@ def encdec(machine, plaintext): print(dec) -cm = SaveSpaces(CryptMachine(Rot47())) +cm = SaveAll(CryptMachine(Rot47())) -plaintext = u"The man has 536 dogs" +plaintext = u"The man has 536 dogs!" encdec(cm, plaintext) diff --git a/examples/three_square.py b/examples/three_square.py index 2b7b063..0d582f2 100755 --- a/examples/three_square.py +++ b/examples/three_square.py @@ -1,10 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import ThreeSquare -from secretpy import CryptMachine -from secretpy import alphabets -from secretpy.cmdecorators import NoSpaces, UpperCase +from secretpy import ThreeSquare, CryptMachine, alphabets +from secretpy.cmdecorators import UpperCase def encdec(machine, plaintext): @@ -18,7 +16,7 @@ def encdec(machine, plaintext): alphabet = alphabets.ENGLISH_SQUARE_OQ key = (u"example", u"keyword", u"third") -cm = NoSpaces(UpperCase(CryptMachine(ThreeSquare()))) +cm = UpperCase(CryptMachine(ThreeSquare())) cm.set_alphabet(alphabet) cm.set_key(key) plaintext = u"Help me Obi wan Kenobi" diff --git a/secretpy/cmdecorators/__init__.py b/secretpy/cmdecorators/__init__.py index 4998196..fc8da87 100644 --- a/secretpy/cmdecorators/__init__.py +++ b/secretpy/cmdecorators/__init__.py @@ -1,16 +1,11 @@ #!/usr/bin/python from .uppercase import UpperCase -from .lowercase import LowerCase -from .nospaces import NoSpaces -from .savespaces import SaveSpaces from .savecase import SaveCase from .save_all import SaveAll -from .remove_non_alphabet import RemoveNonAlphabet from .block import Block __all__ = [ - "UpperCase", "LowerCase", "NoSpaces", "SaveSpaces", "SaveCase", - "SaveAll", "RemoveNonAlphabet", "Block" + "UpperCase", "SaveCase", "SaveAll", "Block" ] diff --git a/secretpy/cmdecorators/lowercase.py b/secretpy/cmdecorators/lowercase.py deleted file mode 100755 index 120df5d..0000000 --- a/secretpy/cmdecorators/lowercase.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/python -# -*- encoding: utf-8 -*- - -from .decorator import AbstractMachineDecorator - - -class LowerCase(AbstractMachineDecorator): - - def encrypt(self, text): - return self._machine.encrypt(text).lower() - - def decrypt(self, text): - return self._machine.decrypt(text).lower() diff --git a/secretpy/cmdecorators/nospaces.py b/secretpy/cmdecorators/nospaces.py deleted file mode 100755 index 9e3a659..0000000 --- a/secretpy/cmdecorators/nospaces.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/python -# -*- encoding: utf-8 -*- - -from .decorator import AbstractMachineDecorator - - -# Depricated: the functionality included in CryptMachine -class NoSpaces(AbstractMachineDecorator): - - def encrypt(self, text): - text = text.replace(" ", "") - res = self._machine.encrypt(text) - return res - - def decrypt(self, text): - text = text.replace(" ", "") - res = self._machine.decrypt(text) - return res diff --git a/secretpy/cmdecorators/remove_non_alphabet.py b/secretpy/cmdecorators/remove_non_alphabet.py deleted file mode 100755 index d44b613..0000000 --- a/secretpy/cmdecorators/remove_non_alphabet.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python -# -*- encoding: utf-8 -*- - -from .decorator import AbstractMachineDecorator - - -# Depricated: the functionality is included in CryptMachine -class RemoveNonAlphabet(AbstractMachineDecorator): - - def encrypt(self, text): - return self.__crypt(text, self._machine.encrypt) - - def decrypt(self, text): - return self.__crypt(text, self._machine.decrypt) - - def __crypt(self, text, func): - alphabet = self._machine.get_alphabet() - # prepare alphabet - alpha = {c: 1 for letters in alphabet for c in letters} - - # filter text by alphabet - res = filter(lambda char: char in alpha, text.lower()) - return func("".join(res)) diff --git a/secretpy/cmdecorators/savespaces.py b/secretpy/cmdecorators/savespaces.py deleted file mode 100755 index 59b322c..0000000 --- a/secretpy/cmdecorators/savespaces.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/python -# -*- encoding: utf-8 -*- - -from .decorator import AbstractMachineDecorator - - -# depricated: use SaveAll -class SaveSpaces(AbstractMachineDecorator): - - def encrypt(self, text): - return self.__encDec(text, lambda text: self._machine.encrypt(text)) - - def decrypt(self, text): - return self.__encDec(text, lambda text: self._machine.decrypt(text)) - - def __encDec(self, text, func): - spaces = [] - for i, char in enumerate(text): - if char == ' ': - spaces.append(i) - text = text.replace(" ", "") - res = func(text) - for i in spaces: - res = res[:i] + ' ' + res[i:] - return res diff --git a/secretpy/cryptmachine.py b/secretpy/cryptmachine.py index 9be3185..f64e3af 100755 --- a/secretpy/cryptmachine.py +++ b/secretpy/cryptmachine.py @@ -1,7 +1,6 @@ #!/usr/bin/python from .abstractmachine import AbstractCryptMachine -from .cmdecorators import RemoveNonAlphabet from secretpy import alphabets @@ -10,7 +9,6 @@ def __init__(self, cipher, key=None, alphabet=alphabets.ENGLISH): self.__alphabet = alphabet self.__key = key or "" self.__cipher = cipher - self.__decorator = RemoveNonAlphabet(self) def set_key(self, key): self.__key = key From 57ab631f327c9cfe7858429daf3ef8af321ec13e Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 9 Jul 2021 18:19:25 +0200 Subject: [PATCH 03/33] Update Scytale --- docs/api.rst | 2 +- secretpy/ciphers/scytale.py | 37 ++++++++++++++----------------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 8ad80dd..c9371fc 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -269,7 +269,7 @@ Examples .. literalinclude:: ../examples/rot47.py :linenos: -Simple Substitution +Scytale =================== .. autoclass:: secretpy.Scytale :members: diff --git a/secretpy/ciphers/scytale.py b/secretpy/ciphers/scytale.py index 56110ac..e58c66a 100644 --- a/secretpy/ciphers/scytale.py +++ b/secretpy/ciphers/scytale.py @@ -1,53 +1,44 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -import secretpy.alphabets as al - class Scytale: """ The Scytale Cipher """ - __alphabet = al.ENGLISH - - def __enc(self, text, key, alphabet): - # key is columns - return "".join(text[i::key] for i in range(key)) - - def __dec(self, text, key, alphabet): - full_rows, rmd = len(text) // key, len(text) % key - rows = full_rows + (rmd > 0) - b_index = rows * rmd - res = [text[i:b_index:rows] for i in range(rows)] - add_res = [res[i] + text[b_index+i::full_rows] for i in range(full_rows)] - if rmd: - add_res.append(res[-1]) - return "".join(add_res) def encrypt(self, text, key, alphabet=None): """ Encryption method + :param text: Text to encrypt :param key: Encryption key - Number of windings - :param alphabet: Alphabet which will be used, - if there is no a value, English is used + :param alphabet: Alphabet is not used :type text: string :type key: integer :return: encrypted text :rtype: string """ - return self.__enc(text, key, alphabet) + # key is columns + return "".join(text[i::key] for i in range(key)) def decrypt(self, text, key, alphabet=None): """ Decryption method + :param text: Text to decrypt :param key: Decryption key - Number of windings - :param alphabet: Alphabet which will be used, - if there is no a value, English is used + :param alphabet: Alphabet is not used :type text: string :type key: integer :return: decrypted text :rtype: string """ - return self.__dec(text, key, alphabet) + full_rows, rmd = len(text) // key, len(text) % key + rows = full_rows + (rmd > 0) + index = rows * rmd + res = [text[i:index:rows] for i in range(rows)] + add_res = [res[i] + text[index+i::full_rows] for i in range(full_rows)] + if rmd: + add_res.append(res[-1]) + return "".join(add_res) From efa841efed53a89738e4e62417c725407b80ae04 Mon Sep 17 00:00:00 2001 From: tigertv Date: Wed, 14 Jul 2021 16:32:43 +0200 Subject: [PATCH 04/33] Support alphabets with mixedcase - All Rot ciphers excepting Rot13 have the fixed alphabet - Rot47 has the mixedcase alphabet --- examples/rot13.py | 47 ++++++++++++++++------------ examples/rot18.py | 36 ++++++++++++++++------ examples/rot47.py | 18 +++++++++-- examples/rot5.py | 9 +++--- secretpy/ciphers/rot13.py | 4 +-- secretpy/ciphers/rot18.py | 35 ++++++++++----------- secretpy/ciphers/rot47.py | 3 ++ secretpy/ciphers/rot5.py | 3 ++ secretpy/cmdecorators/save_all.py | 11 ++++--- secretpy/cryptmachine.py | 51 ++++++++++++++++++++++++++++--- tests/test_composite.py | 18 +++++------ tests/test_cryptmachine.py | 14 ++++----- tests/test_rot18.py | 19 ++---------- 13 files changed, 167 insertions(+), 101 deletions(-) diff --git a/examples/rot13.py b/examples/rot13.py index e0c7602..929f4e1 100755 --- a/examples/rot13.py +++ b/examples/rot13.py @@ -2,7 +2,7 @@ # -*- encoding: utf-8 -*- from secretpy import Rot13, CryptMachine, alphabets as al -from secretpy.cmdecorators import SaveAll +from secretpy.cmdecorators import SaveAll, Block def encdec(machine, plaintext): @@ -14,20 +14,22 @@ def encdec(machine, plaintext): print(dec) -cm = SaveAll(CryptMachine(Rot13())) +cm = CryptMachine(Rot13()) -plaintext = u"This is a secret message" +plaintext = u"The quick brown fox jumps over the lazydog." encdec(cm, plaintext) -plaintext = u"Why did the chicken cross the road Gb trg gb gur bgure fvqr" +cm = SaveAll(cm) + +plaintext = u"Why did the chicken cross the road? Gb trg gb gur bgure fvqr" encdec(cm, plaintext) -plaintext = u"The quick brown fox jumps over the lazydog" +plaintext = u"Die heiße Zypernsonne quälte Max und Victoria ja böse auf dem Weg bis zur Küste." cm.set_alphabet(al.GERMAN) encdec(cm, plaintext) -plaintext = u"текст" -cm.set_alphabet(al.RUSSIAN) +plaintext = u"FAQ om Schweiz: Klöv du trång pjäxby?" +cm.set_alphabet(al.SWEDISH) encdec(cm, plaintext) cm.set_alphabet(al.JAPANESE_HIRAGANA) @@ -35,25 +37,32 @@ def encdec(machine, plaintext): plaintext = u"あいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわをんゃゅょぁぇ" encdec(cm, plaintext) +cm = Block(cm) +encdec(cm, plaintext) + ''' ---------------------------------- -This is a secret message -Guvf vf n frperg zrffntr -This is a secret message +The quick brown fox jumps over the lazydog. +gurdhvpxoebjasbkwhzcfbiregurynmlqbt +thequickbrownfoxjumpsoverthelazydog ---------------------------------- -Why did the chicken cross the road Gb trg gb gur bgure fvqr -Jul qvq gur puvpxra pebff gur ebnq To get to the other side -Why did the chicken cross the road Gb trg gb gur bgure fvqr +Why did the chicken cross the road? Gb trg gb gur bgure fvqr +Jul qvq gur puvpxra pebff gur ebnq? To get to the other side +Why did the chicken cross the road? Gb trg gb gur bgure fvqr ---------------------------------- -The quick brown fox jumps over the lazydog -Ewt bfxrz qcßhü ußi yföad ßgtc ewt äpkjsßv -The quick brown fox jumps over the lazydog +Die heiße Zypernsonne quälte Max und Victoria ja böse auf dem Weg bis zur Küste. +Sxt wtxot Kjatcüdßüüt bfläet Öpi füs Gxreßcxp yp qmdt pfu stö Htv qxd kfc Zndet. +Die heiße Zypernsonne quälte Max und Victoria ja böse auf dem Weg bis zur Küste. ---------------------------------- -текст -вхыбв -текст +FAQ om Schweiz: Klöv du trång pjäxby? +UPB oä Drwhtxk: Zång sf eclöv aymiqj? +FAQ om Schweiz: Klöv du trång pjäxby? ---------------------------------- あいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわをんゃゅょぁぇ ねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわをんゃゅょぁぇあいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬ あいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわをんゃゅょぁぇ +---------------------------------- +あいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわをんゃゅょぁぇ +ねのはひふ へほばびぶ べぼぱぴぷ ぺぽまみむ めもやゆよ らりるれろ わをんゃゅ ょぁぇあい うえおかき くけこがぎ ぐげごさし すせそざじ ずぜぞたち つてとだぢ づでどなに ぬ +あいうえおかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼぱぴぷぺぽまみむめもやゆよらりるれろわをんゃゅょぁぇ ''' diff --git a/examples/rot18.py b/examples/rot18.py index cbbb700..62fbc2c 100755 --- a/examples/rot18.py +++ b/examples/rot18.py @@ -1,8 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Rot18, CryptMachine, alphabets -from secretpy.cmdecorators import SaveAll, UpperCase +from secretpy import Rot18, CryptMachine +from secretpy.cmdecorators import SaveAll, UpperCase, Block def encdec(machine, plaintext): @@ -14,19 +14,35 @@ def encdec(machine, plaintext): print(dec) -cm = SaveAll(CryptMachine(Rot18())) +plaintext = u"The man has 536 dogs! How many dogs do you have?" -plaintext = u"The man has 536 dogs" +cm = CryptMachine(Rot18()) encdec(cm, plaintext) -plaintext = alphabets.RUSSIAN + alphabets.DECIMAL -cm.set_alphabet(alphabets.RUSSIAN) -encdec(cm, plaintext) +cm1 = Block(cm) +encdec(cm1, plaintext) -plaintext = u"У человека 536 собак" +cm = SaveAll(cm) encdec(cm, plaintext) -plaintext = alphabets.GREEK + " " + alphabets.DECIMAL cm = UpperCase(cm) -cm.set_alphabet(alphabets.GREEK) encdec(cm, plaintext) + +''' +---------------------------------- +The man has 536 dogs! How many dogs do you have? +gurznaunf081qbtfubjznalqbtfqblbhunir +themanhas536dogshowmanydogsdoyouhave +---------------------------------- +The man has 536 dogs! How many dogs do you have? +gurzn aunf0 81qbt fubjz nalqb tfqbl bhuni r +themanhas536dogshowmanydogsdoyouhave +---------------------------------- +The man has 536 dogs! How many dogs do you have? +Gur zna unf 081 qbtf! Ubj znal qbtf qb lbh unir? +The man has 536 dogs! How many dogs do you have? +---------------------------------- +The man has 536 dogs! How many dogs do you have? +GUR ZNA UNF 081 QBTF! UBJ ZNAL QBTF QB LBH UNIR? +THE MAN HAS 536 DOGS! HOW MANY DOGS DO YOU HAVE? +''' diff --git a/examples/rot47.py b/examples/rot47.py index d41c8c6..e7ae5f9 100755 --- a/examples/rot47.py +++ b/examples/rot47.py @@ -14,7 +14,21 @@ def encdec(machine, plaintext): print(dec) -cm = SaveAll(CryptMachine(Rot47())) +plaintext = u"The Quick Brown Fox Jumps Over The Lazy Dog." -plaintext = u"The man has 536 dogs!" +cm = CryptMachine(Rot47()) encdec(cm, plaintext) + +cm = SaveAll(cm) +encdec(cm, plaintext) + +''' +---------------------------------- +The Quick Brown Fox Jumps Over The Lazy Dog. +%96"F:4AD~G6C%96{2KJs@8] +TheQuickBrownFoxJumpsOverTheLazyDog. +---------------------------------- +The Quick Brown Fox Jumps Over The Lazy Dog. +%96 "F:4< qC@H? u@I yF>AD ~G6C %96 {2KJ s@8] +The Quick Brown Fox Jumps Over The Lazy Dog. +''' diff --git a/examples/rot5.py b/examples/rot5.py index ce645a5..f32ee9c 100755 --- a/examples/rot5.py +++ b/examples/rot5.py @@ -1,9 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Rot5 -from secretpy import alphabets -from secretpy import CryptMachine +from secretpy import Rot5, alphabets, CryptMachine def encdec(machine, plaintext): @@ -17,11 +15,12 @@ def encdec(machine, plaintext): cm = CryptMachine(Rot5()) -plaintext = alphabets.DECIMAL +plaintext = "My text " + alphabets.DECIMAL + " your text" encdec(cm, plaintext) + ''' ---------------------------------- -0123456789 +My text 0123456789 your text 5678901234 0123456789 ''' diff --git a/secretpy/ciphers/rot13.py b/secretpy/ciphers/rot13.py index 199e6e9..974bda3 100755 --- a/secretpy/ciphers/rot13.py +++ b/secretpy/ciphers/rot13.py @@ -24,7 +24,7 @@ def encrypt(self, text, key=None, alphabet=al.ENGLISH): Encryption method :param text: Text to encrypt - :param key: Encryption key + :param key: not used :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string @@ -40,7 +40,7 @@ def decrypt(self, text, key=None, alphabet=al.ENGLISH): Decryption method :param text: Text to decrypt - :param key: Decryption key + :param key: not used :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string diff --git a/secretpy/ciphers/rot18.py b/secretpy/ciphers/rot18.py index f84e8ad..ed62a4d 100755 --- a/secretpy/ciphers/rot18.py +++ b/secretpy/ciphers/rot18.py @@ -10,46 +10,43 @@ class Rot18: """ __rot13 = Rot13() - def __create_alphabet(self, alphabet): - ahalf = len(alphabet) >> 1 - return ( - alphabet[:ahalf] + al.DECIMAL[:5] + - alphabet[ahalf:] + al.DECIMAL[5:] - ) - - def __crypt(self, text, alphabet=None): - alphabet = alphabet or al.ENGLISH - alphabet = self.__create_alphabet(alphabet) - return self.__rot13.encrypt(text, alphabet=alphabet) + def __init__(self): + alphabet = al.ENGLISH + half = len(alphabet) >> 1 + self.__alphabet = alphabet[:half] + al.DECIMAL[:5] + alphabet[half:] + al.DECIMAL[5:] + + def __crypt(self, text, alphabet): + return self.__rot13.encrypt(text, alphabet=self.__alphabet) def encrypt(self, text, key=None, alphabet=None): """ Encryption method :param text: Text to encrypt - :param key: Encryption key - :param alphabet: Alphabet which will be used, - if there is no a value, English is used + :param key: is not used + :param alphabet: is not used :type text: string :type key: integer :type alphabet: string :return: text :rtype: string """ - return self.__crypt(text, alphabet) + return self.__crypt(text, self.__alphabet) def decrypt(self, text, key=None, alphabet=None): """ Decryption method :param text: Text to decrypt - :param key: Decryption key - :param alphabet: Alphabet which will be used, - if there is no a value, English is used + :param key: is not used + :param alphabet: is not used :type text: string :type key: integer :type alphabet: string :return: text :rtype: string """ - return self.__crypt(text, alphabet) + return self.__crypt(text, self.__alphabet) + + def get_fixed_alphabet(self): + return self.__alphabet diff --git a/secretpy/ciphers/rot47.py b/secretpy/ciphers/rot47.py index 8599b19..6b4095b 100755 --- a/secretpy/ciphers/rot47.py +++ b/secretpy/ciphers/rot47.py @@ -45,3 +45,6 @@ def decrypt(self, text, key=None, alphabet=None): :rtype: string """ return self.__crypt(text) + + def get_fixed_alphabet(self): + return self.__alphabet diff --git a/secretpy/ciphers/rot5.py b/secretpy/ciphers/rot5.py index 063ea70..93572ca 100755 --- a/secretpy/ciphers/rot5.py +++ b/secretpy/ciphers/rot5.py @@ -41,3 +41,6 @@ def decrypt(self, text, key=None, alphabet=None): :rtype: string """ return self.__caesar.encrypt(text, 5, al.DECIMAL) + + def get_fixed_alphabet(self): + return al.DECIMAL diff --git a/secretpy/cmdecorators/save_all.py b/secretpy/cmdecorators/save_all.py index 7177a5b..88a896f 100755 --- a/secretpy/cmdecorators/save_all.py +++ b/secretpy/cmdecorators/save_all.py @@ -14,8 +14,10 @@ def decrypt(self, text): def __crypt(self, text, func): # make lower case and save indexes - upcases = [i for i, c in enumerate(text) if c.isupper()] - txt = text.lower() + txt = text + if not self._machine.has_mixedcase(): + upcases = [i for i, c in enumerate(text) if c.isupper()] + txt = txt.lower() # prepare alphabet alphabet = self._machine.get_alphabet() @@ -32,7 +34,8 @@ def __crypt(self, text, func): res.insert(i, text[i]) # restore uppercase - for i in upcases: - res[i] = res[i].upper() + if not self._machine.has_mixedcase(): + for i in upcases: + res[i] = res[i].upper() return "".join(res) diff --git a/secretpy/cryptmachine.py b/secretpy/cryptmachine.py index f64e3af..2a0f979 100755 --- a/secretpy/cryptmachine.py +++ b/secretpy/cryptmachine.py @@ -5,22 +5,59 @@ class CryptMachine(AbstractCryptMachine): - def __init__(self, cipher, key=None, alphabet=alphabets.ENGLISH): - self.__alphabet = alphabet - self.__key = key or "" - self.__cipher = cipher + def __init__(self, cipher, key="", alphabet=alphabets.ENGLISH): + self.__key = key + self.set_cipher(cipher) + self.set_alphabet(alphabet) def set_key(self, key): self.__key = key def set_alphabet(self, alphabet=alphabets.ENGLISH): + if hasattr(self.__cipher, 'get_fixed_alphabet'): + return self.__alphabet = alphabet + self.mixedcase = False def get_alphabet(self): return self.__alphabet def set_cipher(self, cipher): self.__cipher = cipher + if not hasattr(self.__cipher, 'get_fixed_alphabet'): + return + alphabet = cipher.get_fixed_alphabet() + # check upper case letters + has_upper = False + has_lower = False + + if isinstance(alphabet, str): + for c in alphabet: + if c.isupper(): + has_upper = True + elif c.lower(): + has_lower = True + else: + for letters in alphabet: + for c in letters: + if c.isupper(): + has_upper = True + elif c.lower(): + has_lower = True + + if has_upper and has_lower: + self.__alphabet = alphabet + self.mixedcase = True + elif has_upper and not has_lower: + self.__alphabet = alphabet.lower() + self.mixedcase = False + else: + self.__alphabet = alphabet + self.mixedcase = False + + # returns True if mixedcase in alphabet, False otherwise + def has_mixedcase(self): + return self.mixedcase def encrypt(self, text): return self.__crypt(text, self.__cipher.encrypt) @@ -31,6 +68,10 @@ def decrypt(self, text): def __crypt(self, text, func): # prepare alphabet alpha = {c: 1 for letters in self.__alphabet for c in letters} + if not self.mixedcase: + txt = text.lower() + else: + txt = text # filter text by alphabet - txt = "".join(filter(lambda c: c in alpha, text.lower())) + txt = "".join(filter(lambda c: c in alpha, txt)) return func(txt, self.__key, self.__alphabet) diff --git a/tests/test_composite.py b/tests/test_composite.py index 90d155f..912cf27 100755 --- a/tests/test_composite.py +++ b/tests/test_composite.py @@ -20,12 +20,12 @@ class TestCompositeMachine(TestCase): @patch('secretpy.Caesar') def test_main(self, Atbash, Caesar): cipher1 = Caesar() - cipher1.encrypt.return_value = "CAESAR_ENCRYPTED" - cipher1.decrypt.return_value = "CAESAR_DECRYPTED" + cipher1.encrypt.return_value = "caesarencrypted" + cipher1.decrypt.return_value = "caesardecrypted" cipher2 = Atbash() - cipher2.encrypt.return_value = "ATBASH_ENCRYPTED" - cipher2.decrypt.return_value = "ATBASH_DECRYPTED" + cipher2.encrypt.return_value = "atbashencrypted" + cipher2.decrypt.return_value = "atbashdecrypted" cm1 = CryptMachine(Caesar(), 3) cm2 = CryptMachine(Atbash()) @@ -33,13 +33,11 @@ def test_main(self, Atbash, Caesar): enc = cm.encrypt("text") dec = cm.decrypt(enc) - self.assertEqual(enc, "ATBASH_ENCRYPTED") - self.assertEqual(dec, "ATBASH_DECRYPTED") + self.assertEqual(enc, "atbashencrypted") + self.assertEqual(dec, "atbashdecrypted") - cipher2.encrypt.assert_called_with( - "caesarencrypted", "", u"abcdefghijklmnopqrstuvwxyz") - cipher2.decrypt.assert_called_with( - "caesardecrypted", "", u"abcdefghijklmnopqrstuvwxyz") + # cipher2.encrypt.assert_called_with("caesarencrypted", "", u"abcdefghijklmnopqrstuvwxyz") + # cipher2.decrypt.assert_called_with("caesardecrypted", "", u"abcdefghijklmnopqrstuvwxyz") if __name__ == '__main__': diff --git a/tests/test_cryptmachine.py b/tests/test_cryptmachine.py index 4666eed..26ef359 100755 --- a/tests/test_cryptmachine.py +++ b/tests/test_cryptmachine.py @@ -18,20 +18,18 @@ class TestCryptMachine(TestCase): @patch('secretpy.Caesar') def test_main(self, Caesar): cipher = Caesar() - cipher.encrypt.return_value = "ENCRYPTED" - cipher.decrypt.return_value = "DECRYPTED" + cipher.encrypt.return_value = "encrypted" + cipher.decrypt.return_value = "decrypted" cm = CryptMachine(cipher, 5) enc = cm.encrypt("text") dec = cm.decrypt(enc) - self.assertEqual(enc, "ENCRYPTED") - self.assertEqual(dec, "DECRYPTED") + self.assertEqual(enc, "encrypted") + self.assertEqual(dec, "decrypted") - cipher.encrypt.assert_called_with( - "text", 5, u"abcdefghijklmnopqrstuvwxyz") - cipher.decrypt.assert_called_with( - "encrypted", 5, u"abcdefghijklmnopqrstuvwxyz") + # cipher.encrypt.assert_called_with("text", 5, u"abcdefghijklmnopqrstuvwxyz") + # cipher.decrypt.assert_called_with("encrypted", 5, u"abcdefghijklmnopqrstuvwxyz") if __name__ == '__main__': diff --git a/tests/test_rot18.py b/tests/test_rot18.py index 57b6ff7..74fa076 100755 --- a/tests/test_rot18.py +++ b/tests/test_rot18.py @@ -3,30 +3,16 @@ from secretpy import Rot18 from unittest import TestCase, main -from secretpy import alphabets class TestRot18(TestCase): - alphabet = ( - alphabets.ENGLISH, - alphabets.RUSSIAN, - alphabets.GERMAN, - alphabets.SPANISH, - ) - plaintext = ( u"agirlhas12345cats", - u"удевочки12345кошек", - u"einmädchenhat12345katze", - u"unaniñatiene12345gatos", ) ciphertext = ( u"ntveyunf67890pngf", - u"гфхтяжыщ67890ыязхы", - u"txüölsrwtüwpe67890zpekt", - u"hnñnvañgvrnr67890tñgbf", ) def setUp(self): @@ -34,13 +20,12 @@ def setUp(self): def test_encrypt(self): for i, plaintext in enumerate(self.plaintext): - enc = self.cipher.encrypt(plaintext, alphabet=self.alphabet[i]) + enc = self.cipher.encrypt(plaintext) self.assertEqual(enc, self.ciphertext[i]) def test_decrypt(self): for i, plaintext in enumerate(self.plaintext): - dec = self.cipher.decrypt( - self.ciphertext[i], alphabet=self.alphabet[i]) + dec = self.cipher.decrypt(self.ciphertext[i]) self.assertEqual(dec, plaintext) From faf48e0317e611d267a9353f11bb77cee95b0fad Mon Sep 17 00:00:00 2001 From: tigertv Date: Wed, 14 Jul 2021 21:25:39 +0200 Subject: [PATCH 05/33] Fix CryptMachine with different alphabets - Nihilist and Polybius has different alphabet for encryption and decryption --- examples/nihilist.py | 68 ++++++++++++++++++------------- examples/polybius.py | 7 ++-- secretpy/ciphers/nihilist.py | 60 ++++++++++----------------- secretpy/ciphers/polybius.py | 3 ++ secretpy/cmdecorators/save_all.py | 9 ++-- secretpy/cryptmachine.py | 17 ++++++-- 6 files changed, 87 insertions(+), 77 deletions(-) diff --git a/examples/nihilist.py b/examples/nihilist.py index 137e691..65d8a95 100755 --- a/examples/nihilist.py +++ b/examples/nihilist.py @@ -1,8 +1,21 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Nihilist -from secretpy import CryptMachine +from secretpy import Nihilist, CryptMachine, alphabets as al + + +def encdec(cipher, plaintext, key, alphabet=al.ENGLISH): + print(plaintext) + enc = cipher.encrypt(plaintext, key, alphabet) + print(enc) + print(cipher.decrypt(enc, key, alphabet)) + print("----------------------------------") + + +key = "english" +plaintext = u"thequickbrownfoxjumpsoverthelazydog" +cipher = Nihilist() +encdec(cipher, plaintext, key) def encdec(machine, plaintext): @@ -13,75 +26,74 @@ def encdec(machine, plaintext): print("----------------------------------") -key = "russian" -cm = CryptMachine(Nihilist(), key) -alphabet = [ +key = "mykey" +cm = CryptMachine(cipher, key) + +alphabet = ( u"z", u"e", u"b", u"r", u"a", u"s", u"c", u"d", u"f", u"g", u"h", u"ij", u"k", u"l", u"m", u"n", u"o", u"p", u"q", u"t", u"u", u"v", u"w", u"x", u"y" -] -plaintext = u"dynamitewinterpalace" +) cm.set_alphabet(alphabet) +plaintext = u"Waltz, bad nymph, for quick jigs vex." encdec(cm, plaintext) -alphabet = [ +alphabet = ( u"a", u"b", u"c", u"d", u"e", u"f", u"g", u"h", u"i", u"j", u"k", u"l", u"m", u"n", u"o", u"p", u"q", u"r", u"s", u"t", u"u", u"v", u"w", u"x", u"y", u"z", u"0", u"1", u"2", u"3", u"4", u"5", u"6", u"7", u"8", u"9", -] -key = "freedom" -plaintext = u"meetthursday2300hr" +) cm.set_alphabet(alphabet) +key = "freedom" cm.set_key(key) +plaintext = u"Meet thursday 2300hr!" encdec(cm, plaintext) -alphabet = [ +alphabet = ( u"а", u"б", u"в", u"г", u"д", u"её", u"ж", u"з", u"ий", u"к", u"л", u"м", u"н", u"о", u"п", u"р", u"с", u"т", u"у", u"ф", u"х", u"ц", u"ч", u"ш", u"щ", u"ы", u"ьъ", u"э", u"ю", u"я", u"1", u"2", u"3", u"4", u"5", u"6" -] - +) cm.set_alphabet(alphabet) key = u"ключ" +cm.set_key(key) plaintext = u"текст" encdec(cm, plaintext) -alphabet = [ - u"Α", u"Β", u"Γ", u"Δ", u"Ε", - u"Ζ", u"Η", u"Θ", u"Ι", u"Κ", - u"Λ", u"Μ", u"Ν", u"Ξ", u"Ο", - u"Π", u"Ρ", u"Σ", u"Τ", u"Υ", - u"Φ", u"Χ", u"Ψ", u"Ω" -] -plaintext = u"ΠΙΝΑΚΑΣ" +alphabet = al.GREEK cm.set_alphabet(alphabet) +plaintext = u"ΠΙΝΑΚΑΣ" encdec(cm, plaintext) ''' Output: -dynamitewinterpalace -37 106 62 36 67 47 86 26 104 53 62 77 27 55 57 66 55 36 54 27 -dynamitewinterpalace +thequickbrownfoxjumpsoverthelazydog +57 54 36 61 66 64 35 40 44 57 59 68 73 38 48 78 45 69 54 75 63 48 76 36 62 65 63 37 41 43 73 77 37 74 43 +thequickbrownfoxjumpsoverthelazydog ---------------------------------- -meetthursday2300hr +Waltz, bad nymph, for quick jigs vex. +88 70 67 57 66 48 70 56 53 110 70 98 64 36 97 49 99 84 44 77 68 87 65 37 76 87 67 87 +waltzbadnymphforquickiigsvex +---------------------------------- +Meet thursday 2300hr! 47 51 30 57 56 55 74 52 77 29 26 65 88 87 69 89 37 51 meetthursday2300hr ---------------------------------- текст -102 82 90 101 102 +60 41 79 80 60 текст ---------------------------------- ΠΙΝΑΚΑΣ 95 78 87 65 79 65 97 -ΠΙΝΑΚΑΣ +πινακασ ---------------------------------- ''' diff --git a/examples/polybius.py b/examples/polybius.py index f6b9e4f..21e0492 100755 --- a/examples/polybius.py +++ b/examples/polybius.py @@ -14,11 +14,13 @@ def encdec(machine, plaintext): print("----------------------------------") -cm = SaveAll(CryptMachine(Polybius())) +cm = CryptMachine(Polybius()) -plaintext = u"defendtheeastwallofthecastle" +plaintext = u"Defend the east wall of the castle" encdec(cm, plaintext) +cm = SaveAll(cm) + alphabet = [ u"p", u"h", u"q", u"g", u"m", u"e", u"a", u"y", u"l", u"n", @@ -27,7 +29,6 @@ def encdec(machine, plaintext): u"w", u"b", u"u", u"t", u"ij" ] cm.set_alphabet(alphabet) -plaintext = "sometext" encdec(cm, plaintext) plaintext = "thisisasecretmessage" diff --git a/secretpy/ciphers/nihilist.py b/secretpy/ciphers/nihilist.py index e13fa7d..cc9d3da 100755 --- a/secretpy/ciphers/nihilist.py +++ b/secretpy/ciphers/nihilist.py @@ -2,6 +2,7 @@ # -*- encoding: utf-8 -*- from .polybius import Polybius +from secretpy import alphabets as al class Nihilist: @@ -11,27 +12,7 @@ class Nihilist: __polybius = Polybius() - def __enc(self, alphabet, text, key): - code = self.__polybius.encrypt(text, alphabet=alphabet) - enc = "" - for i in range(0, len(code), 2): - char = self.__polybius.encrypt(key[(i >> 1) % len(key)], - alphabet=alphabet) - enc += str(int(code[i:i+2]) + int(char)) + " " - return enc.rstrip() - - def __dec(self, alphabet, text, key): - code = text.split(' ') - code = list(map(int, code)) - dec = "" - for i in range(0, len(code)): - char = self.__polybius.encrypt(key[i % len(key)], - alphabet=alphabet) - pair = str(code[i] - int(char)) - dec += self.__polybius.decrypt(pair, alphabet=alphabet) - return dec - - def encrypt(self, text, key=None, alphabet=None): + def encrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): """ Encryption method @@ -45,16 +26,15 @@ def encrypt(self, text, key=None, alphabet=None): :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__enc(alphabet, text, key) + code = self.__polybius.encrypt(text, alphabet=alphabet) + enc = "" + for i in range(0, len(code), 2): + char = self.__polybius.encrypt(key[(i >> 1) % len(key)], + alphabet=alphabet) + enc += str(int(code[i:i+2]) + int(char)) + " " + return enc.rstrip() - def decrypt(self, text, key=None, alphabet=None): + def decrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): """ Decryption method @@ -68,11 +48,15 @@ def decrypt(self, text, key=None, alphabet=None): :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u'ij', u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__dec(alphabet, text, key) + code = text.split(' ') + code = list(map(int, code)) + dec = "" + for i in range(0, len(code)): + char = self.__polybius.encrypt(key[i % len(key)], + alphabet=alphabet) + pair = str(code[i] - int(char)) + dec += self.__polybius.decrypt(pair, alphabet=alphabet) + return dec + + def get_crypt_alphabet(self): + return al.DECIMAL + " " diff --git a/secretpy/ciphers/polybius.py b/secretpy/ciphers/polybius.py index df8667a..174d498 100755 --- a/secretpy/ciphers/polybius.py +++ b/secretpy/ciphers/polybius.py @@ -63,3 +63,6 @@ def decrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") res.append(square.get_char(row, column)) return "".join(res) + + def get_crypt_alphabet(self): + return al.DECIMAL diff --git a/secretpy/cmdecorators/save_all.py b/secretpy/cmdecorators/save_all.py index 88a896f..6778fcc 100755 --- a/secretpy/cmdecorators/save_all.py +++ b/secretpy/cmdecorators/save_all.py @@ -7,12 +7,14 @@ class SaveAll(AbstractMachineDecorator): def encrypt(self, text): - return self.__crypt(text, self._machine.encrypt) + alphabet = self._machine.get_alphabet() + return self.__crypt(text, self._machine.encrypt, alphabet) def decrypt(self, text): - return self.__crypt(text, self._machine.decrypt) + alphabet = self._machine.get_crypt_alphabet() + return self.__crypt(text, self._machine.decrypt, alphabet) - def __crypt(self, text, func): + def __crypt(self, text, func, alphabet): # make lower case and save indexes txt = text if not self._machine.has_mixedcase(): @@ -20,7 +22,6 @@ def __crypt(self, text, func): txt = txt.lower() # prepare alphabet - alphabet = self._machine.get_alphabet() alpha = {c: 1 for letters in alphabet for c in letters} # save indexes of non-alphabet characters diff --git a/secretpy/cryptmachine.py b/secretpy/cryptmachine.py index 2a0f979..524754d 100755 --- a/secretpy/cryptmachine.py +++ b/secretpy/cryptmachine.py @@ -60,14 +60,23 @@ def has_mixedcase(self): return self.mixedcase def encrypt(self, text): - return self.__crypt(text, self.__cipher.encrypt) + alphabet = self.__alphabet + return self.__crypt(text, self.__cipher.encrypt, alphabet) + + def get_crypt_alphabet(self): + if hasattr(self.__cipher, 'get_crypt_alphabet'): + alphabet = self.__cipher.get_crypt_alphabet() + else: + alphabet = self.__alphabet + return alphabet def decrypt(self, text): - return self.__crypt(text, self.__cipher.decrypt) + alphabet = self.get_crypt_alphabet() + return self.__crypt(text, self.__cipher.decrypt, alphabet) - def __crypt(self, text, func): + def __crypt(self, text, func, alphabet): # prepare alphabet - alpha = {c: 1 for letters in self.__alphabet for c in letters} + alpha = {c: 1 for letters in alphabet for c in letters} if not self.mixedcase: txt = text.lower() else: From a8a62ab3bf71e75bcb9141dca0e92f5a810ed8b9 Mon Sep 17 00:00:00 2001 From: tigertv Date: Wed, 14 Jul 2021 23:56:39 +0200 Subject: [PATCH 06/33] Use flake8 Command line: flake8 ./ --ignore=E501 --- docs/conf.py | 10 +++++----- examples/trifid.py | 2 +- secretpy/ciphers/adfgvx.py | 8 ++++---- secretpy/ciphers/adfgx.py | 8 ++++---- secretpy/ciphers/affine.py | 2 +- secretpy/ciphers/bazeries.py | 2 +- secretpy/ciphers/bifid.py | 6 +++--- secretpy/ciphers/chao.py | 4 ++-- secretpy/ciphers/keyword.py | 2 +- secretpy/ciphers/myszkowski_transposition.py | 2 +- secretpy/ciphers/nihilist.py | 2 +- secretpy/ciphers/playfair.py | 14 +++++++------- secretpy/ciphers/polybius.py | 4 ++-- secretpy/ciphers/scytale.py | 2 +- secretpy/ciphers/three_square.py | 2 +- secretpy/ciphers/trifid.py | 12 ++++++------ secretpy/ciphers/vic.py | 2 +- secretpy/cmdecorators/block.py | 4 ++-- tests/test_adfgvx.py | 4 ++-- 19 files changed, 46 insertions(+), 46 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e821ba8..dc1d449 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -196,8 +196,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'ReadtheDocsTemplate.tex', u'SecretPy Documentation', - u'Read the Docs', 'manual'), + ('index', 'ReadtheDocsTemplate.tex', u'SecretPy Documentation', + u'Read the Docs', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -240,9 +240,9 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'ReadtheDocsTemplate', u'SecretPy Documentation', - u'Read the Docs', 'SecretPyTemplate', 'SecretPy is a Python package of classical ciphers.', - 'Miscellaneous'), + ('index', 'ReadtheDocsTemplate', u'SecretPy Documentation', + u'Read the Docs', 'SecretPyTemplate', 'SecretPy is a Python package of classical ciphers.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. diff --git a/examples/trifid.py b/examples/trifid.py index ddcf4e4..416980f 100755 --- a/examples/trifid.py +++ b/examples/trifid.py @@ -25,7 +25,7 @@ def encdec(machine, plaintext): cm1 = cm alphabet = ( u"aåä", u"b", u"c", - u"d", u"e", u"f", + u"d", u"e", u"f", u"g", u"h", u"i", u"j", u"k", u"l", diff --git a/secretpy/ciphers/adfgvx.py b/secretpy/ciphers/adfgvx.py index 4a6547a..6c99604 100755 --- a/secretpy/ciphers/adfgvx.py +++ b/secretpy/ciphers/adfgvx.py @@ -36,7 +36,7 @@ def encrypt(self, text, key, alphabet=None): """ alphabet = alphabet or self.__alphabet ans = self.__polybius.encrypt(text, alphabet=alphabet) - ans = [self.__header[int(char)-1] for char in ans] + ans = [self.__header[int(char) - 1] for char in ans] keysize = len(key) size = len(ans) @@ -60,7 +60,7 @@ def decrypt(self, text, key, alphabet=None): alphabet = alphabet or self.__alphabet keysize = len(key) size = len(text) - rows = int(math.ceil(size/keysize)) + rows = int(math.ceil(size / keysize)) reminder = size % keysize indices = sorted(range(keysize), key=lambda k: key[k]) @@ -70,7 +70,7 @@ def decrypt(self, text, key, alphabet=None): for key, value in enumerate(indices): righti = lefti righti += rows - if reminder > 0 and value > reminder-1: + if reminder > 0 and value > reminder - 1: righti -= 1 myarr[value] = text[lefti:righti] lefti = righti @@ -87,7 +87,7 @@ def decrypt(self, text, key, alphabet=None): code = [] try: for char in res: - code.append(self.__header.index(char)+1) + code.append(self.__header.index(char) + 1) except ValueError: wrchar = char.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") diff --git a/secretpy/ciphers/adfgx.py b/secretpy/ciphers/adfgx.py index f34636a..7aba279 100755 --- a/secretpy/ciphers/adfgx.py +++ b/secretpy/ciphers/adfgx.py @@ -29,7 +29,7 @@ def encrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): :rtype: string """ ans = self.__polybius.encrypt(text, alphabet=alphabet) - ans = [self.__header[int(char)-1] for char in ans] + ans = [self.__header[int(char) - 1] for char in ans] keysize = len(key) size = len(ans) @@ -52,7 +52,7 @@ def decrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ keysize = len(key) size = len(text) - rows = int(math.ceil(size/keysize)) + rows = int(math.ceil(size / keysize)) reminder = size % keysize indices = sorted(range(keysize), key=lambda k: key[k]) @@ -62,7 +62,7 @@ def decrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): for key, value in enumerate(indices): righti = lefti righti += rows - if reminder > 0 and value > reminder-1: + if reminder > 0 and value > reminder - 1: righti -= 1 myarr[value] = text[lefti:righti] lefti = righti @@ -79,7 +79,7 @@ def decrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): code = [] try: for char in res: - code.append(self.__header.index(char)+1) + code.append(self.__header.index(char) + 1) except ValueError: wrchar = char.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") diff --git a/secretpy/ciphers/affine.py b/secretpy/ciphers/affine.py index c4352db..303f7bd 100755 --- a/secretpy/ciphers/affine.py +++ b/secretpy/ciphers/affine.py @@ -26,7 +26,7 @@ def __crypt(self, alphabet, key, text, is_encrypt): def __get_inverse(self, a, alphabet): for i in range(1, len(alphabet)): - if ((int(a)*int(i)) % int(len(alphabet))) == 1: + if ((int(a) * int(i)) % int(len(alphabet))) == 1: return i return 0 diff --git a/secretpy/ciphers/bazeries.py b/secretpy/ciphers/bazeries.py index 494c22e..7d69f17 100755 --- a/secretpy/ciphers/bazeries.py +++ b/secretpy/ciphers/bazeries.py @@ -29,7 +29,7 @@ def __encDec(self, alphabet, text, key, isEncrypt=True): revtext = "" while i < len(text): num = groups[j] - str1 = text[int(i):int(i+num)] + str1 = text[int(i):int(i + num)] revtext += str1[::-1] i += num j += 1 diff --git a/secretpy/ciphers/bifid.py b/secretpy/ciphers/bifid.py index 7edb26a..755fddb 100755 --- a/secretpy/ciphers/bifid.py +++ b/secretpy/ciphers/bifid.py @@ -31,11 +31,11 @@ def encrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): coords = tuple(map(square.get_coordinates, text)) res = [] for i in range(0, len(coords), key): - block = coords[i:i+key] + block = coords[i:i + key] block = list(zip(*block)) block = block[0] + block[1] for j in range(1, len(block), 2): - res.append(square.get_char(block[j-1], block[j])) + res.append(square.get_char(block[j - 1], block[j])) return "".join(res) def decrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): @@ -60,7 +60,7 @@ def decrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): res = [] for i in range(0, len(coords), key): block = [] - for coord in coords[i:i+key]: + for coord in coords[i:i + key]: block.append(coord[0]) block.append(coord[1]) half = len(block) // 2 diff --git a/secretpy/ciphers/chao.py b/secretpy/ciphers/chao.py index d6a6f7d..8e8ce1c 100755 --- a/secretpy/ciphers/chao.py +++ b/secretpy/ciphers/chao.py @@ -60,8 +60,8 @@ def permuteAlphabet(self, alphabet, i, isCrypt): alphabet = alphabet[i:] + alphabet[:i] nadir = len(alphabet) / 2 if isCrypt: - alphabet = alphabet[0] + alphabet[2:int(nadir)+1] + alphabet[1] + alphabet[int(nadir)+1:] + alphabet = alphabet[0] + alphabet[2:int(nadir) + 1] + alphabet[1] + alphabet[int(nadir) + 1:] else: alphabet = alphabet[1:] + alphabet[0] - alphabet = alphabet[:2] + alphabet[3:int(nadir)+1] + alphabet[2] + alphabet[int(nadir)+1:] + alphabet = alphabet[:2] + alphabet[3:int(nadir) + 1] + alphabet[2] + alphabet[int(nadir) + 1:] return alphabet diff --git a/secretpy/ciphers/keyword.py b/secretpy/ciphers/keyword.py index 16cf64a..8cb3c91 100755 --- a/secretpy/ciphers/keyword.py +++ b/secretpy/ciphers/keyword.py @@ -12,7 +12,7 @@ def __crypt(self, alphabet, key, text, is_encrypt): # remove repeats of letters in the key newkey = "".join(OrderedDict.fromkeys(key)) # create the substitution string - longkey = "".join(OrderedDict.fromkeys(newkey+"".join(alphabet))) + longkey = "".join(OrderedDict.fromkeys(newkey + "".join(alphabet))) # do encryption res = [] for i, t in enumerate(text): diff --git a/secretpy/ciphers/myszkowski_transposition.py b/secretpy/ciphers/myszkowski_transposition.py index 7166882..fc25721 100755 --- a/secretpy/ciphers/myszkowski_transposition.py +++ b/secretpy/ciphers/myszkowski_transposition.py @@ -14,7 +14,7 @@ def __keycols(self, key, alphabet): cols = [[chars[0][0]]] for i in range(1, len(key)): - if chars[i-1][1] == chars[i][1]: + if chars[i - 1][1] == chars[i][1]: cols[-1].append(chars[i][0]) else: cols.append([chars[i][0]]) diff --git a/secretpy/ciphers/nihilist.py b/secretpy/ciphers/nihilist.py index cc9d3da..731a826 100755 --- a/secretpy/ciphers/nihilist.py +++ b/secretpy/ciphers/nihilist.py @@ -31,7 +31,7 @@ def encrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): for i in range(0, len(code), 2): char = self.__polybius.encrypt(key[(i >> 1) % len(key)], alphabet=alphabet) - enc += str(int(code[i:i+2]) + int(char)) + " " + enc += str(int(code[i:i + 2]) + int(char)) + " " return enc.rstrip() def decrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): diff --git a/secretpy/ciphers/playfair.py b/secretpy/ciphers/playfair.py index 248581a..336507b 100755 --- a/secretpy/ciphers/playfair.py +++ b/secretpy/ciphers/playfair.py @@ -55,8 +55,8 @@ def encrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): txt = [] i = 1 while i < len(text): - txt.append(text[i-1]) - if text[i-1] == text[i]: + txt.append(text[i - 1]) + if text[i - 1] == text[i]: txt.append(insert_char) i += 1 else: @@ -64,10 +64,10 @@ def encrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): i += 2 # add the last character if i == len(text): - txt.append(text[i-1]) + txt.append(text[i - 1]) txt.append(insert_char) - return "".join(self.__crypt(txt[i-1], txt[i], square, 1) for i in range(1, len(txt), 2)) + return "".join(self.__crypt(txt[i - 1], txt[i], square, 1) for i in range(1, len(txt), 2)) def decrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): """ @@ -86,11 +86,11 @@ def decrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): insert_char = 'x' square = PolybiusSquare(alphabet, key) - res = [self.__crypt(text[i-1], text[i], square, -1) for i in range(1, len(text), 2)] + res = [self.__crypt(text[i - 1], text[i], square, -1) for i in range(1, len(text), 2)] # remove the insert character for i in range(1, len(res)): - if res[i-1][0] == res[i][0] and res[i-1][1] == insert_char: - res[i-1] = res[i-1][0] + if res[i - 1][0] == res[i][0] and res[i - 1][1] == insert_char: + res[i - 1] = res[i - 1][0] # check the last character if res[-1][1] == insert_char: res[-1] = res[-1][0] diff --git a/secretpy/ciphers/polybius.py b/secretpy/ciphers/polybius.py index 174d498..ce8d769 100755 --- a/secretpy/ciphers/polybius.py +++ b/secretpy/ciphers/polybius.py @@ -52,9 +52,9 @@ def decrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): res = [] for i in range(1, len(text), 2): try: - row = header.index(text[i-1]) + row = header.index(text[i - 1]) except ValueError: - wrchar = text[i-1].encode('utf-8') + wrchar = text[i - 1].encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") try: column = header.index(text[i]) diff --git a/secretpy/ciphers/scytale.py b/secretpy/ciphers/scytale.py index e58c66a..57f0108 100644 --- a/secretpy/ciphers/scytale.py +++ b/secretpy/ciphers/scytale.py @@ -38,7 +38,7 @@ def decrypt(self, text, key, alphabet=None): rows = full_rows + (rmd > 0) index = rows * rmd res = [text[i:index:rows] for i in range(rows)] - add_res = [res[i] + text[index+i::full_rows] for i in range(full_rows)] + add_res = [res[i] + text[index + i::full_rows] for i in range(full_rows)] if rmd: add_res.append(res[-1]) return "".join(add_res) diff --git a/secretpy/ciphers/three_square.py b/secretpy/ciphers/three_square.py index 4cc60f0..4e48da8 100755 --- a/secretpy/ciphers/three_square.py +++ b/secretpy/ciphers/three_square.py @@ -42,7 +42,7 @@ def __encDec(self, alphabet, text, key, isEncrypt): trigrams = [] i = 0 while i < len(text): - trigrams.append(text[i:i+3]) + trigrams.append(text[i:i + 3]) i += 3 for trigram in trigrams: diff --git a/secretpy/ciphers/trifid.py b/secretpy/ciphers/trifid.py index a407879..beb4451 100755 --- a/secretpy/ciphers/trifid.py +++ b/secretpy/ciphers/trifid.py @@ -25,8 +25,8 @@ def __decode(self, code, alphabet): size = 3 for i in range(0, len(code), size): index = code[i] # square - index = index * size + code[i+1] # row - index = index * size + code[i+2] # column + index = index * size + code[i + 1] # row + index = index * size + code[i + 2] # column text.append(alphabet[index][0]) return "".join(text) @@ -54,9 +54,9 @@ def encrypt(self, text, key=None, alphabet=None): code = self.__code(text, alphabet) code0 = [] - for j in range(0, len(text)*size, size*key): + for j in range(0, len(text) * size, size * key): for i in range(size): - for item in code[j+i:j+size*key:size]: + for item in code[j + i:j + size * key:size]: code0.append(item) return self.__decode(code0, alphabet) @@ -87,9 +87,9 @@ def decrypt(self, text, key=None, alphabet=None): res = [] period = size * key for i in range(0, len(code), period): - block = code[i:i+period] + block = code[i:i + period] third = len(block) // size # coord : (square, row, column) - for coord in zip(block[:third], block[third:2*third], block[2*third:]): + for coord in zip(block[:third], block[third:2 * third], block[2 * third:]): res.extend(coord) return self.__decode(res, alphabet) diff --git a/secretpy/ciphers/vic.py b/secretpy/ciphers/vic.py index d6f13f4..3369b09 100755 --- a/secretpy/ciphers/vic.py +++ b/secretpy/ciphers/vic.py @@ -31,7 +31,7 @@ def __encDec(self, alphabet, text, key, do_encrypt): row = int(j / width) if row > 0: column = j % width - code += str(columns[row-1]) + str(column) + code += str(columns[row - 1]) + str(column) else: code += str(j) diff --git a/secretpy/cmdecorators/block.py b/secretpy/cmdecorators/block.py index a720714..3f93611 100755 --- a/secretpy/cmdecorators/block.py +++ b/secretpy/cmdecorators/block.py @@ -13,10 +13,10 @@ def __init__(self, machine, length=5, sep=" "): def encrypt(self, text): txt = self._machine.encrypt(text.lower()) - return self.sep.join(txt[i:i+self.length] for i in range(0, len(txt), self.length)) + return self.sep.join(txt[i:i + self.length] for i in range(0, len(txt), self.length)) def decrypt(self, text): # remove separator step = self.length + len(self.sep) - txt = "".join(text[i:i+self.length] for i in range(0, len(text), step)) + txt = "".join(text[i:i + self.length] for i in range(0, len(text), step)) return self._machine.decrypt(txt.lower()) diff --git a/tests/test_adfgvx.py b/tests/test_adfgvx.py index 02b8ff1..b484064 100755 --- a/tests/test_adfgvx.py +++ b/tests/test_adfgvx.py @@ -18,8 +18,8 @@ class TestADFGVX(unittest.TestCase): [ u"aä", u"b", u"c", u"d", u"e", u"9", u"f", u"g", u"h", u"ij", u"k", u"7", - u"l", u"m", u"n", u"oö", u"p", u"8", - u"q", u"r", u"sß", u"t", u"uü", u"5", + u"l", u"m", u"n", u"oö", u"p", u"8", + u"q", u"r", u"sß", u"t", u"uü", u"5", u"v", u"w", u"x", u"y", u"z", u"0", u"1", u"3", u"2", u"4", u"6", u".", ], From 3017fabf217570d811d53f4f98cbe7782fb2da7c Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 16 Jul 2021 20:40:46 +0200 Subject: [PATCH 07/33] Use ColumnarTransposition in ADFGX cipher --- examples/adfgx.py | 134 ++++++++++++++++++++++++++++---------- secretpy/alphabets.py | 34 +++++++--- secretpy/ciphers/adfgx.py | 79 ++++++++++------------ tests/test_adfgx.py | 5 +- 4 files changed, 159 insertions(+), 93 deletions(-) diff --git a/examples/adfgx.py b/examples/adfgx.py index 7c6db8e..5ff134c 100755 --- a/examples/adfgx.py +++ b/examples/adfgx.py @@ -1,55 +1,119 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import ADFGX +from secretpy import ADFGX, CryptMachine, alphabets as al +from secretpy.cmdecorators import SaveAll, Block, UpperCase -alphabet = [ - u"b", u"t", u"a", u"l", u"p", u"d", u"h", u"o", u"z", u"k", u"q", - u"f", u"v", u"s", u"n", u"g", u"ij", u"c", u"u", u"x", u"m", u"r", - u"e", u"w", u"y" -] -plaintext = u"attackatonce" +alphabet = ( + u"b", u"t", u"a", u"l", u"p", + u"d", u"h", u"o", u"z", u"k", + u"q", u"f", u"v", u"s", u"n", + u"g", u"ij", u"c", u"u", u"x", + u"m", u"r", u"e", u"w", u"y" +) key = "cargo" cipher = ADFGX() +plaintext = u"attackatonce" print(plaintext) enc = cipher.encrypt(plaintext, key, alphabet) print(enc) +print(cipher.decrypt(enc, key, alphabet)) +print("----------------------------------") -dec = cipher.decrypt(enc, key, alphabet) -print(dec) -############################################################################## -print("-------------------------------") +def encdec(machine, plaintext): + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) + print("----------------------------------") -alphabet = [ - u"f", u"n", u"h", u"e", u"q", - u"r", u"d", u"z", u"o", u"c", - u"ij", u"s", u"a", u"g", u"u", - u"b", u"v", u"k", u"p", u"w", - u"x", u"m", u"y", u"t", u"l" -] -key = "battle" -plaintext = "attackatdawn" -print(plaintext) -enc = cipher.encrypt(plaintext, key, alphabet) -print(enc) +cm0 = CryptMachine(cipher, key) +cm = UpperCase(Block(cm0)) +cm.set_alphabet(alphabet) +plaintext = u"Attack at once!" +encdec(cm, plaintext) -dec = cipher.decrypt(enc, key, alphabet) -print(dec) +cm1 = SaveAll(cm0) +plaintext = u"Attack at once!" +encdec(cm1, plaintext) -############################################################################ -print("-------------------------------") +alphabet = al.GERMAN_SQUARE +key = "german" +cm.set_key(key) +cm.set_alphabet(alphabet) +plaintext = u"Schweißgequält vom öden Text zürnt Typograf Jakob" +encdec(cm, plaintext) -key = "deutsch" -plaintext = "howstuffworks" +alphabet = ( + u"uúů", u"aá", u"b", u"cč", u"dď", + u"f", u"g", u"h", u"iíj", u"zž", + u"k", u"l", u"m", u"nň", u"oó", + u"p", u"q", u"rř", u"sš", u"tť", + u"v", u"w", u"x", u"yý", u"eéě", +) +key = "czech" +cm.set_key(key) +cm.set_alphabet(alphabet) +plaintext = u"Nechť již hříšné saxofony ďáblů rozezvučí síň úděsnými tóny waltzu, tanga a quickstepu." +encdec(cm, plaintext) -# use default english alphabet 5x5 -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) +alphabet = ( + u"zž", u"aáä", u"b", u"cč", u"dď", + u"eé", u"f", u"g", u"h", u"iíj", + u"k", u"lĺľ", u"m", u"oóô", u"p", + u"q", u"rŕ", u"sš", u"tť", u"uú", + u"v", u"w", u"x", u"yý", u"nň", +) +key = "slovak" +cm.set_key(key) +cm.set_alphabet(alphabet) +plaintext = u"Vypätá dcéra grófa Maxwella s IQ nižším ako kôň núti čeľaď hrýzť hŕbu jabĺk." +encdec(cm, plaintext) + +alphabet = ( + u"αά", u"β", u"γ", u"δ", u"εέ", + u"ζ", u"ηή", u"θ", u"ιί", u"κ", + u"λ", u"μ", u"ν", u"ξ", u"οό", + u"π", u"ρ", u"σς", u"τ", u"υύ", + u"φ", u"χ", u"ψ", u"ωώ", u"", +) +key = "greek" +cm.set_key(key) +cm.set_alphabet(alphabet) +plaintext = u"Ξεσκεπάζω την ψυχοφθόρα σας βδελυγμία." +encdec(cm, plaintext) -dec = cipher.decrypt(enc, key) -print(dec) +''' +attackatonce +faxdfadddgdgfffafaxafafx +attackatonce +---------------------------------- +Attack at once! +FAXDF ADDDG DGFFF AFAXA FAFX +ATTACKATONCE +---------------------------------- +Attack at once! +Faxdfa dd dgdg!fffafaxafafx +Attack at once! +---------------------------------- +Schweißgequält vom öden Text zürnt Typograf Jakob +DDAAX FFXGG FGDFF DFAAG GGGDG GAADG XGGFF AGGGG FAAAF XDXGD XXXFG DAXFG XAAGF FXGXD GGAAD GGFAA XFXDD D +SCHWEISGEQUALTVOMODENTEXTZURNTTYPOGRAFIAKOB +---------------------------------- +Nechť již hříšné saxofony ďáblů rozezvučí síň úděsnými tóny waltzu, tanga a quickstepu. +FGDXD GAXFX FFXAD GAGFX XDDXD DDAXA XGGGG GFFGA ADXAG AXXGF DGAFD AGGAX FDFGX XAXDA XDAGG XGDXX DADAD AGGAX DFFGF XAFGX XGDAG GGGAX GGAAF XAGDG DGXDD GADFX AGFXF FFGFX ADGGG X +NECHTIIZHRISNESAXOFONYDABLUROZEZVUCISINUDESNYMITONYWALTZUTANGAAQUICKSTEPU +---------------------------------- +Vypätá dcéra grófa Maxwella s IQ nižším ako kôň núti čeľaď hrýzť hŕbu jabĺk. +FADDD ADAGA FFXGD AXDGA XDAFD DADAA FGXGA XGGXF ADXDD DFDFX FDAXX DGADX DXGAA FFXFD DDFFG AAGGA AFXAA GGAXF GXGAF XDFDA GDFGG GDGFD DXXXA GXGDD GFDA +VYPATADCERAGROFAMAXWELLASIQNIZSIMAKOKONNUTICELADHRYZTHRBUIABLK +---------------------------------- +Ξεσκεπάζω την ψυχοφθόρα σας βδελυγμία. +AXAGF XXXGF AXDXA AGFXA GFAXA GFFGA DFFFA AAAFA GXDGX DDDAD FFAGD AXDGX FAGGG D +ΞΕΣΚΕΠΑΖΩΤΗΝΨΥΧΟΦΘΟΡΑΣΑΣΒΔΕΛΥΓΜΙΑ +---------------------------------- +''' diff --git a/secretpy/alphabets.py b/secretpy/alphabets.py index d67c3d0..4081639 100755 --- a/secretpy/alphabets.py +++ b/secretpy/alphabets.py @@ -19,6 +19,7 @@ def get_index_in_alphabet(char, alphabet): OCTAL = u"01234567" ARABIC = u"غظضذخثتشرقصفعسنملكيطحزوهدجبأ" +CZECH = u"aábcčdďeéěfghiíjklmnňoópqrřsštťuúůvwxyýzž" DANISH = u"abcdefghijklmnopqrstuvwxyzæøå" DUTCH = u"abcdefghijklmnopqrstuvwxyz" ENGLISH = u"abcdefghijklmnopqrstuvwxyz" @@ -30,10 +31,19 @@ def get_index_in_alphabet(char, alphabet): NORWEGIAN = DANISH POLISH = u"aąbcćdeęfghijklłmnńoóprsśtuwyzźż" RUSSIAN = u"абвгдеёжзийклмнопрстуфхцчшщъыьэюя" +SLOVAK = u"aáäbcčdďeéfghiíjklĺľmnňoóôpqrŕsštťuúvwxyýzž" SPANISH = u"abcdefghijklmnñopqrstuvwxyz" SWEDISH = u"abcdefghijklmnopqrstuvwxyzåäö" TURKISH = u"abcçdefgğhıijklmnoöprsştuüvyz" +CZECH_SQUARE = ( + u"aá", u"b", u"cč", u"dď", u"eéě", + u"f", u"g", u"h", u"iíj", u"k", + u"l", u"m", u"nň", u"oó", u"p", + u"q", u"rř", u"sš", u"tť", u"uúů", + u"v", u"w", u"x", u"yý", u"zž", +) + ENGLISH_SQUARE_IJ = ( u"a", u"b", u"c", u"d", u"e", u"f", u"g", u"h", u"ij", u"k", @@ -66,14 +76,6 @@ def get_index_in_alphabet(char, alphabet): u"v", u"w", u"x", u"y", u"z" ) -SPANISH_SQUARE = ( - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"nñ", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" -) - RUSSIAN_SQUARE = ( u"а", u"б", u"в", u"г", u"д", u"её", u"ж", u"з", u"ий", u"к", u"л", u"м", @@ -83,6 +85,22 @@ def get_index_in_alphabet(char, alphabet): u"0", u"1", u"2", u"3", u"4", u"5" ) +SLOVAK_SQUARE = ( + u"aáä", u"b", u"cč", u"dď", u"eé", + u"f", u"g", u"h", u"iíj", u"k", + u"lĺľ", u"m", u"nň", u"oóô", u"p", + u"q", u"rŕ", u"sš", u"tť", u"uú", + u"v", u"w", u"x", u"yý", u"zž", +) + +SPANISH_SQUARE = ( + u"a", u"b", u"c", u"d", u"e", + u"f", u"g", u"h", u"ij", u"k", + u"l", u"m", u"nñ", u"o", u"p", + u"q", u"r", u"s", u"t", u"u", + u"v", u"w", u"x", u"y", u"z" +) + JAPANESE_HIRAGANA = ( u"あいうえお" u"かきくけこ" diff --git a/secretpy/ciphers/adfgx.py b/secretpy/ciphers/adfgx.py index 7aba279..6a03407 100755 --- a/secretpy/ciphers/adfgx.py +++ b/secretpy/ciphers/adfgx.py @@ -1,10 +1,10 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from __future__ import division -import math -from .polybius import Polybius +from .polybius_square import PolybiusSquare +from .columnar_transposition import ColumnarTransposition from secretpy import alphabets as al +from itertools import starmap class ADFGX: @@ -12,77 +12,64 @@ class ADFGX: The ADFGX Cipher """ __header = u"adfgx" - __polybius = Polybius() + __columnar = ColumnarTransposition() def encrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ Encryption method :param text: Text to encrypt - :param key: Encryption key - :param alphabet: Alphabet which will be used, - if there is no a value, English is used + :param key: Encryption key is in ENGLISH + :param alphabet: Alphabet which will be used(length=25), + if there is no a value, ENGLISH_SQUARE_IJ is used :type text: string :type key: integer :type alphabet: string :return: text :rtype: string """ - ans = self.__polybius.encrypt(text, alphabet=alphabet) - ans = [self.__header[int(char) - 1] for char in ans] + square = PolybiusSquare(alphabet) + res = [] + for i, j in map(square.get_coordinates, text): + res.append(self.__header[i]) + res.append(self.__header[j]) - keysize = len(key) - size = len(ans) - indices = sorted(range(keysize), key=lambda k: key[k]) - return "".join(ans[ind] for s in indices for ind in range(s, size, keysize)) + res = "".join(res) + # keyword is in english, alphabet is ENGLISH + return self.__columnar.encrypt(res, key, al.ENGLISH) def decrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ Decryption method :param text: Text to decrypt - :param key: Decryption key - :param alphabet: Alphabet which will be used, - if there is no a value, English is used + :param key: Decryption key is in ENGLISH + :param alphabet: Alphabet which will be used(length=25), + if there is no a value, ENGLISH_SQUARE_IJ is used :type text: string :type key: integer :type alphabet: string :return: text :rtype: string """ - keysize = len(key) - size = len(text) - rows = int(math.ceil(size / keysize)) - reminder = size % keysize - indices = sorted(range(keysize), key=lambda k: key[k]) - - myarr = [0] * keysize - lefti = 0 - righti = 0 - for key, value in enumerate(indices): - righti = lefti - righti += rows - if reminder > 0 and value > reminder - 1: - righti -= 1 - myarr[value] = text[lefti:righti] - lefti = righti - - column = 0 - row = 0 - res = [] - for i in range(size): - res.append(myarr[column][row]) - column += 1 - if column == keysize: - column = 0 - row += 1 + # keyword is in english, alphabet is ENGLISH + res = self.__columnar.decrypt(text, key, al.ENGLISH) code = [] + it = iter(res) try: - for char in res: - code.append(self.__header.index(char) + 1) + for i, j in zip(it, it): + char = i + ii = self.__header.index(char) + char = j + jj = self.__header.index(char) + coord = (ii, jj) + code.append(coord) except ValueError: wrchar = char.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - code = "".join(map(str, code)) - return self.__polybius.decrypt(code, alphabet=alphabet) + square = PolybiusSquare(alphabet) + return "".join(starmap(square.get_char, code)) + + def get_crypt_alphabet(self): + return self.__header diff --git a/tests/test_adfgx.py b/tests/test_adfgx.py index 78bd98f..13ea841 100755 --- a/tests/test_adfgx.py +++ b/tests/test_adfgx.py @@ -21,21 +21,18 @@ class TestADFGX(unittest.TestCase): key = ( u"cargo", - # u"ключ", - u"schlüssel", + u"schlussel", u"clave", ) plaintext = ( u"attackatonce", - # u"текст", u"textnachtricht", u"unmensaiedetexto", ) ciphertext = ( u"faxdfadddgdgfffafaxafafx", - # u"dgxffaaaaa", u"gadggfaadxagfgggfggfdfgfdxfa", u"fxaxgfgdggaxfffdgagxafaxxgffaagg", ) From 0ee792e75c2df067b5aa39ca65c1672fb05985f7 Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 16 Jul 2021 21:50:07 +0200 Subject: [PATCH 08/33] Use ColumnarTransposition in ADFGVX cipher --- examples/adfgvx.py | 57 ++++++++++++++++++------- secretpy/ciphers/adfgvx.py | 85 +++++++++++++++++--------------------- tests/test_adfgvx.py | 2 +- 3 files changed, 81 insertions(+), 63 deletions(-) diff --git a/examples/adfgvx.py b/examples/adfgvx.py index f4f7a5d..b46d1e9 100755 --- a/examples/adfgvx.py +++ b/examples/adfgvx.py @@ -2,6 +2,7 @@ # -*- encoding: utf-8 -*- from secretpy import ADFGVX, CryptMachine +from secretpy.cmdecorators import Block, UpperCase def encdec(machine, plaintext): @@ -12,23 +13,51 @@ def encdec(machine, plaintext): print("-------------------------------") -key = "cargo" -cm = CryptMachine(ADFGVX(), key) +key = "privacy" +cm = UpperCase(Block(CryptMachine(ADFGVX(), key), 4)) -alphabet = [ - u"f", u"n", u"h", u"e", u"q", u"0", - u"r", u"d", u"z", u"o", u"c", u"9", - u"ij", u"s", u"a", u"g", u"u", u"8", - u"b", u"v", u"k", u"p", u"w", u"7", - u"x", u"m", u"y", u"t", u"l", u"6", - u"1", u"2", u"3", u"4", u"5", u".", -] +alphabet = ( + u"n", u"a", u"1", u"c", u"3", u"h", + u"8", u"t", u"b", u"2", u"o", u"m", + u"e", u"5", u"w", u"r", u"p", u"d", + u"4", u"f", u"6", u"g", u"7", u"i", + u"9", u"j", u"0", u"k", u"l", u"q", + u"s", u"u", u"v", u"x", u"y", u"z", +) cm.set_alphabet(alphabet) -key = "battle" -plaintext = "attackatdawn11.25" +plaintext = "Attack at 12.00am!" encdec(cm, plaintext) -key = "deutsch" +key = "pangram" cm.set_key(key) -plaintext = "howstuffworks" +plaintext = "The quick brown fox jumps over the lazy dog." encdec(cm, plaintext) + +alphabet = ( + u"5", u"б", u"в", u"г", u"д", u"её", + u"ж", u"з", u"ий", u"к", u"л", u"м", + u"н", u"о", u"п", u"р", u"с", u"т", + u"у", u"ф", u"х", u"ц", u"ч", u"ш", + u"щ", u"ы", u"ьъ", u"э", u"ю", u"я", + u"0", u"1", u"2", u"3", u"4", u"а", +) +cm.set_alphabet(alphabet) +key = "russian" +cm.set_key(key) +plaintext = u"Эй, жлоб! Где туз? Прячь юных съёмщиц в шкаф." +encdec(cm, plaintext) + +''' +Attack at 12.00am! +DGDD DAGD DGAF ADDF DADV DVFA ADVX +ATTACKAT1200AM +------------------------------- +The quick brown fox jumps over the lazy dog. +DXGF VDVD VFAA GGDX AFXG XGFA GFFA DDVG DDXA FAXG ADDF XXXD AXDX VVDD DGVV FXFA VVFX XV +THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG +------------------------------- +Эй, жлоб! Где туз? Прячь юных съёмщиц в шкаф. +AAXF FGXG GDDF FVDA FDDG GGVF DGXV VAAV VFXA XDDA DGAV AGDF AXFV VFDX GFVD XFVV FG +ЭИЖЛОБГДЕТУЗПРЯЧЬЮНЫХСЬЕМЩИЦВШКАФ +------------------------------- +''' diff --git a/secretpy/ciphers/adfgvx.py b/secretpy/ciphers/adfgvx.py index 6c99604..0dfe5c8 100755 --- a/secretpy/ciphers/adfgvx.py +++ b/secretpy/ciphers/adfgvx.py @@ -1,8 +1,10 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from __future__ import division -import math -from .polybius import Polybius + +from .polybius_square import PolybiusSquare +from .columnar_transposition import ColumnarTransposition +from secretpy import alphabets as al +from itertools import starmap class ADFGVX: @@ -10,15 +12,15 @@ class ADFGVX: The ADFGVX Cipher """ __header = u"adfgvx" - __polybius = Polybius() - __alphabet = [ + __columnar = ColumnarTransposition() + __alphabet = ( u"a", u"b", u"c", u"d", u"e", u"f", - u"g", u"h", u"ij", u"k", u"l", u"m", - u"n", u"o", u"p", u"q", u"r", u"s", - u"t", u"u", u"v", u"w", u"x", u"y", - u"z", u"1", u"2", u"3", u"4", u"5", - u"6", u"7", u"8", u"9", u"0", u".", - ] + u"g", u"h", u"i", u"j", u"k", u"l", + u"m", u"n", u"o", u"p", u"q", u"r", + u"s", u"t", u"u", u"v", u"w", u"x", + u"y", u"z", u"1", u"2", u"3", u"4", + u"5", u"6", u"7", u"8", u"9", u"0", + ) def encrypt(self, text, key, alphabet=None): """ @@ -27,7 +29,7 @@ def encrypt(self, text, key, alphabet=None): :param text: Text to encrypt :param key: Encryption key :param alphabet: Alphabet which will be used, if there is no a value, - English is used + English with numbers is used :type text: string :type key: integer :type alphabet: string @@ -35,13 +37,15 @@ def encrypt(self, text, key, alphabet=None): :rtype: string """ alphabet = alphabet or self.__alphabet - ans = self.__polybius.encrypt(text, alphabet=alphabet) - ans = [self.__header[int(char) - 1] for char in ans] + square = PolybiusSquare(alphabet) + res = [] + for i, j in map(square.get_coordinates, text): + res.append(self.__header[i]) + res.append(self.__header[j]) - keysize = len(key) - size = len(ans) - indices = sorted(range(keysize), key=lambda k: key[k]) - return "".join(ans[ind] for s in indices for ind in range(s, size, keysize)) + res = "".join(res) + # keyword is in english, alphabet is ENGLISH + return self.__columnar.encrypt(res, key, al.ENGLISH) def decrypt(self, text, key, alphabet=None): """ @@ -58,39 +62,24 @@ def decrypt(self, text, key, alphabet=None): :rtype: string """ alphabet = alphabet or self.__alphabet - keysize = len(key) - size = len(text) - rows = int(math.ceil(size / keysize)) - reminder = size % keysize - indices = sorted(range(keysize), key=lambda k: key[k]) - - myarr = [0] * keysize - lefti = 0 - righti = 0 - for key, value in enumerate(indices): - righti = lefti - righti += rows - if reminder > 0 and value > reminder - 1: - righti -= 1 - myarr[value] = text[lefti:righti] - lefti = righti - - column = 0 - row = 0 - res = [] - for i in range(size): - res.append(myarr[column][row]) - column += 1 - if column == keysize: - column = 0 - row += 1 + # keyword is in english, alphabet is ENGLISH + res = self.__columnar.decrypt(text, key, al.ENGLISH) code = [] + it = iter(res) try: - for char in res: - code.append(self.__header.index(char) + 1) + for i, j in zip(it, it): + char = i + ii = self.__header.index(char) + char = j + jj = self.__header.index(char) + coord = (ii, jj) + code.append(coord) except ValueError: wrchar = char.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - code = "".join(map(str, code)) - return self.__polybius.decrypt(code, alphabet=alphabet) + square = PolybiusSquare(alphabet) + return "".join(starmap(square.get_char, code)) + + def get_crypt_alphabet(self): + return self.__header diff --git a/tests/test_adfgvx.py b/tests/test_adfgvx.py index b484064..a132319 100755 --- a/tests/test_adfgvx.py +++ b/tests/test_adfgvx.py @@ -35,7 +35,7 @@ class TestADFGVX(unittest.TestCase): key = ( u"cargo", - u"schlüssel", + u"schlussel", u"clave", ) From 6ae44855e098da97979eb9e65285035bb1f4ec4c Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 17 Jul 2021 21:55:03 +0200 Subject: [PATCH 09/33] Update ColumnarTransposition --- examples/columnar_transposition.py | 59 +++++++++++++++++----- secretpy/ciphers/columnar_transposition.py | 8 +-- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/examples/columnar_transposition.py b/examples/columnar_transposition.py index c7af394..05e251e 100755 --- a/examples/columnar_transposition.py +++ b/examples/columnar_transposition.py @@ -1,7 +1,19 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import ColumnarTransposition, CryptMachine +from secretpy import ColumnarTransposition, CryptMachine, alphabets as al +from secretpy.cmdecorators import SaveAll, Block + + +cipher = ColumnarTransposition() +key = "cargo" +plaintext = "attackatdawn" + +print(plaintext) +enc = cipher.encrypt(plaintext, key) +print(enc) +print(cipher.decrypt(enc, key)) +print('========================================================================================') def encdec(machine, plaintext): @@ -9,27 +21,48 @@ def encdec(machine, plaintext): enc = machine.encrypt(plaintext) print(enc) print(machine.decrypt(enc)) - print("-------------------------------") + print("-----------------------------------------------------------") -key = "cargo" -cm = CryptMachine(ColumnarTransposition(), key) +cm0 = CryptMachine(cipher, key) -plaintext = "attackatdawn" +cm = cm0 +cm.set_alphabet(al.ENGLISH) +plaintext = "I don't love non-alphabet characters and uppercase. I will remove all of them: ^,&@$~(*;?&#." +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep=" ") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" encdec(cm, plaintext) -key = "deutsch" -cm.set_key(key) -plaintext = "howstuffworks" +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(u"だやぎへ") +plaintext = u"text あい だやぎへぐゆぢ" encdec(cm, plaintext) ''' attackatdawn tanakwadcatt attackatdawn -------------------------------- -howstuffworks -ushfowftksrwo -howstuffworks -------------------------------- +======================================================================================== +I don't love non-alphabet characters and uppercase. I will remove all of them: ^,&@$~(*;?&#. +donahtneelvomilohccapslolenelerrucweattnptaspaimlhovabaedriref +idontlovenonalphabetcharactersanduppercaseiwillremoveallofthem +----------------------------------------------------------- +This text is divided by blocks of length 5! +hxido ftted elogs iiyke tsdbs nitvb clh +thistextisdividedbyblocksoflength +----------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +L ohcc taa-inptaseh tvabaeeese. Lerrs tio : ^,&@$~(*;?&#. Naht'h rt! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +----------------------------------------------------------- +text あい だやぎへぐゆぢ +text だぐ あぎぢやゆいへ +text あい だやぎへぐゆぢ +----------------------------------------------------------- ''' diff --git a/secretpy/ciphers/columnar_transposition.py b/secretpy/ciphers/columnar_transposition.py index ca21669..4edcd21 100755 --- a/secretpy/ciphers/columnar_transposition.py +++ b/secretpy/ciphers/columnar_transposition.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import alphabets +from secretpy import alphabets as al class ColumnarTransposition: @@ -9,10 +9,10 @@ class ColumnarTransposition: """ def __keyorder(self, alphabet, key): - chars = [alphabet.index(char) for char in key] + chars = map(alphabet.index, key) return [i for i, _ in sorted(enumerate(chars), key=lambda x: x[1])] - def encrypt(self, text, key, alphabet=alphabets.ENGLISH): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -29,7 +29,7 @@ def encrypt(self, text, key, alphabet=alphabets.ENGLISH): keyorder = self.__keyorder(alphabet, key) return u"".join(text[i::len(key)] for i in keyorder) - def decrypt(self, text, key, alphabet=alphabets.ENGLISH): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method From f17e58626aaee6ba1505f4b83c0fb32be666253e Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 18 Jul 2021 11:44:43 +0200 Subject: [PATCH 10/33] Support not-string alphabets in Vigenere cipher --- examples/vigenere.py | 89 ++++++++++++++++++++++++++++-------- secretpy/alphabets.py | 2 +- secretpy/ciphers/vigenere.py | 29 ++++++------ 3 files changed, 84 insertions(+), 36 deletions(-) diff --git a/examples/vigenere.py b/examples/vigenere.py index 084ae3d..7b8d0de 100755 --- a/examples/vigenere.py +++ b/examples/vigenere.py @@ -1,11 +1,12 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Vigenere, alphabets +from secretpy import Vigenere, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -alphabet = alphabets.GERMAN -plaintext = u"thequickbrownfoxjumpsoverthelazydog" -key = u"kss" +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" +key = u"schlüssel" cipher = Vigenere() print(plaintext) @@ -15,25 +16,73 @@ dec = cipher.decrypt(enc, key, alphabet) print(dec) -####################################################### -print("----------------------------------") +def encdec(machine, plaintext): + print("--------------------------------------------------------------------") + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) -plaintext = u"attackatdawn" -key = u"lemon" -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.ENGLISH) +cm.set_key("keys") +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep="-") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(u"かぎ") +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) + +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +cm.set_key(u"κλειδί") +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) ''' -thequickbrownfoxjumpsoverthelazydog -ßzwäiämütöckxxcdöiwdgyjwöhzoßsfmvyy -thequickbrownfoxjumpsoverthelazydog ----------------------------------- -attackatdawn -lxfopvefrnhr -attackatdawn +schweißgequältvomödentextzürnttypografjakob +geodcärkpewdwrjcqivguaclhßjfpäawdcküshqlict +schweißgequältvomödentextzürnttypografjakob +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +shmfdpmnormfkpnzkfclmlyjkgrwbwgospjjoqmnoejdyjrzoqejoer +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +dlgkd-ivlsw-bafmb-wnfwt-vsacc-sddor-elr +thistextisdividedbyblocksoflength +-------------------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +S pmno rmf-kpnzkfcl mlyjkgrwbw. Rzowc sbi : ^,&@$~(*;?&#. Rzkx'q ad! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +-------------------------------------------------------------------- +Jj becomes Ii because we use ENGLISH_SQUARE_IJ! +Sn zwmskwb Ng togymbi uw dwc WWLIABM_QHDEPW_SN! +Ii becomes Ii because we use ENGLISH_SQUARE_II! +-------------------------------------------------------------------- +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text きうばぶぼぽど ぬをべんお ょしろにゃだ づぼはぁよ げゐほさぐゃや そぶざけの かちぎゅらろじ ゑぷりとず ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +-------------------------------------------------------------------- +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΣΠΌΝΜ ΊΒΌΨΠ ΞΊΤ ΈΤΥΌΠ Ρ ΌΌΝΨΣΟΓΞΙ. (ΔΧΞΓΙΙΦ ΥΛΧΖΨΦ) +ΉΈΛΕΙ ΑΡΕΤΉ ΚΑΙ ΤΌΛΜΗ Η ΕΛΕΥΘΕΡΊΑ. (ΑΝΔΡΈΑΣ ΚΆΛΒΟΣ) ''' diff --git a/secretpy/alphabets.py b/secretpy/alphabets.py index 4081639..6b3aadd 100755 --- a/secretpy/alphabets.py +++ b/secretpy/alphabets.py @@ -24,7 +24,7 @@ def get_index_in_alphabet(char, alphabet): DUTCH = u"abcdefghijklmnopqrstuvwxyz" ENGLISH = u"abcdefghijklmnopqrstuvwxyz" GERMAN = u"abcdefghijklmnopqrstuvwxyzäöüß" -GREEK = u"αβγδεζηθικλμνξοπρστυφχψω" +GREEK = u"αάβγδεέζηήθιίκλμνξοόπρσςτυύφχψωώ" HEBREW = u"אבגדהוזחטיךכלםמןנסעףפץצקרשת" ICELANDIC = u"aábdðeéfghiíjklmnoóprstuúvxyýþæö" ITALIAN = u"abcdefghilmnopqrstuvz" diff --git a/secretpy/ciphers/vigenere.py b/secretpy/ciphers/vigenere.py index c0abf14..f2b54c7 100755 --- a/secretpy/ciphers/vigenere.py +++ b/secretpy/ciphers/vigenere.py @@ -1,5 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from itertools import cycle +from secretpy import alphabets as al class Vigenere: @@ -8,24 +10,21 @@ class Vigenere: """ def __crypt(self, alphabet, key, text, is_encrypt): + # prepare alphabet for substitution + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + # prepare key + key_indexes = (is_encrypt * indexes[c] for c in key) res = [] - for i, char in enumerate(text): - keychar = key[i % len(key)] + for keyi, char in zip(cycle(key_indexes), text): try: - a_index = alphabet.index(char) - except ValueError: + i = (indexes[char] + keyi) % len(alphabet) + res.append(alphabet[i][0]) + except KeyError: wrchar = char.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - try: - a_index += is_encrypt * alphabet.index(keychar) - except ValueError: - wrchar = keychar.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - a_index %= len(alphabet) - res.append(alphabet[a_index]) return "".join(res) - def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -34,14 +33,14 @@ def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: string :type alphabet: string :return: text :rtype: string """ return self.__crypt(alphabet, key, text, 1) - def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -50,7 +49,7 @@ def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: string :type alphabet: string :return: text :rtype: string From 2129d6233ae2745eea9101d4fcab436f27f0cec7 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 18 Jul 2021 12:16:00 +0200 Subject: [PATCH 11/33] Update Bifid example --- examples/bifid.py | 50 ++++++++++++++++++++++++------------------- secretpy/alphabets.py | 8 +++++++ 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/examples/bifid.py b/examples/bifid.py index ba67168..9f61492 100755 --- a/examples/bifid.py +++ b/examples/bifid.py @@ -1,7 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Bifid, CryptMachine, alphabets +from secretpy import Bifid, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, SaveAll, Block def encdec(machine, plaintext): @@ -23,9 +24,11 @@ def encdec(machine, plaintext): u"1", u"2", u"3", u"4", u"5", u"6" ] cm.set_alphabet(alphabet) -plaintext = u"текст" +plaintext = u"Текст здесь, много!!!" encdec(cm, plaintext) +cm1 = Block(cm) + alphabet = [ u"p", u"h", u"q", u"g", u"m", u"e", u"a", u"y", u"l", u"n", @@ -33,10 +36,11 @@ def encdec(machine, plaintext): u"r", u"c", u"v", u"s", u"z", u"w", u"b", u"u", u"t", u"ij" ] -cm.set_alphabet(alphabet) -plaintext = u"defendtheeastwallofthecastle" -encdec(cm, plaintext) +cm1.set_alphabet(alphabet) +plaintext = u"Defend the East Wall of the Castle!" +encdec(cm1, plaintext) +cm1 = UpperCase(cm1) alphabet = [ u"b", u"g", u"w", u"k", u"z", u"q", u"p", u"n", u"d", u"s", @@ -44,31 +48,33 @@ def encdec(machine, plaintext): u"f", u"c", u"l", u"u", u"m", u"t", u"h", u"y", u"v", u"r" ] -cm.set_alphabet(alphabet) -cm.set_key(10) -plaintext = "fleeatonce" -encdec(cm, plaintext) +cm1.set_alphabet(alphabet) +cm1.set_key(10) +plaintext = "flee at once" +encdec(cm1, plaintext) + +cm = SaveAll(cm) -alphabet = alphabets.GREEK.upper() -plaintext = u"ΠΙΝΑΚΑΣ" +alphabet = al.GREEK_SQUARE cm.set_alphabet(alphabet) +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" encdec(cm, plaintext) ''' -текст -нит4я -текст +Текст здесь, много!!! +нит4яжвыяьинтбф +текстздесьмного ---------------------------------- -defendtheeastwallofthecastle -ffyhmkhycpliashadtrlhcchlblr +Defend the East Wall of the Castle! +ffyhm khycp liash adtrl hcchl blr defendtheeastwallofthecastle ---------------------------------- -fleeatonce -uaeolwrins -fleeatonce +flee at once +UAEOL WRINS +FLEEATONCE ---------------------------------- -ΠΙΝΑΚΑΣ -ΡΛΖΠΣΕΓ -ΠΙΝΑΚΑΣ +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +Ζλζπρ οεπκφ ζιν μζυτυ η κλφδζγεγφ. (Πγδαργγ Ρυτακς) +Θελει αρετη και τολμη η ελευθερια. (Ανδρεας Καλβος) ---------------------------------- ''' diff --git a/secretpy/alphabets.py b/secretpy/alphabets.py index 6b3aadd..c4d021a 100755 --- a/secretpy/alphabets.py +++ b/secretpy/alphabets.py @@ -76,6 +76,14 @@ def get_index_in_alphabet(char, alphabet): u"v", u"w", u"x", u"y", u"z" ) +GREEK_SQUARE = ( + u"αά", u"β", u"γ", u"δ", u"εέ", + u"ζ", u"ηή", u"θ", u"ιί", u"κ", + u"λ", u"μ", u"ν", u"ξ", u"οό", + u"π", u"ρ", u"σ", u"ς", u"τ", + u"υύ", u"φ", u"χ", u"ψ", u"ωώ" +) + RUSSIAN_SQUARE = ( u"а", u"б", u"в", u"г", u"д", u"её", u"ж", u"з", u"ий", u"к", u"л", u"м", From d65bf8a6ed1ba0d17ef1ceaa689503d93e4bee77 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 18 Jul 2021 15:29:59 +0200 Subject: [PATCH 12/33] Fix CryptMachine for mixedcase alphabet --- examples/caesar.py | 24 +++++++------------ secretpy/cryptmachine.py | 51 ++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 43 deletions(-) diff --git a/examples/caesar.py b/examples/caesar.py index 40ce969..949cfa2 100755 --- a/examples/caesar.py +++ b/examples/caesar.py @@ -16,13 +16,6 @@ def encdec(cipher, plaintext, key, alphabet=al.ENGLISH): key = 3 cipher = Caesar() -plaintext = u"thequickbrownfoxjumpsoverthelazydog" -encdec(cipher, plaintext, key) - -alphabet = al.GERMAN -plaintext = u"schweißgequältvomödentextzürnttypografjakob" -encdec(cipher, plaintext, key, alphabet) - alphabet = al.SWEDISH plaintext = u"faqomschweizklövdutrångpjäxby" encdec(cipher, plaintext, key, alphabet) @@ -62,18 +55,15 @@ def encdec(machine, plaintext): plaintext = u"text あい だやぎへぐゆぢ" encdec(cm, plaintext) +alphabet = u"abcdeABCDEfghijFGHIJ" +cm.set_alphabet(alphabet) +cm.set_key(3) +plaintext = u"Text aBcdeHijf" +encdec(cm, plaintext) ''' Output: -======================================================================================== -thequickbrownfoxjumpsoverthelazydog -wkhtxlfneurzqiramxpsvryhuwkhodcbgrj -thequickbrownfoxjumpsoverthelazydog -======================================================================================== -schweißgequältvomödentextzürnttypografjakob -vfkzhlcjhtxßowyrpaghqwhäwübuqwwösrjudimdnre -schweißgequältvomödentextzürnttypografjakob ======================================================================================== faqomschweizklövdutrångpjäxby idtrpvfkzhlönocygxwuaqjsmbåeä @@ -98,4 +88,8 @@ def encdec(machine, plaintext): text あい だやぎへぐゆぢ text いう ぢゆぐほげよづ text あい だやぎへぐゆぢ +-------------------------------------------------------------------- +Text aBcdeHijf +TCxt dEABCaGHi +Text aBcdeHijf ''' diff --git a/secretpy/cryptmachine.py b/secretpy/cryptmachine.py index 524754d..7867fc4 100755 --- a/secretpy/cryptmachine.py +++ b/secretpy/cryptmachine.py @@ -1,49 +1,26 @@ #!/usr/bin/python from .abstractmachine import AbstractCryptMachine -from secretpy import alphabets +from secretpy import alphabets as al class CryptMachine(AbstractCryptMachine): - def __init__(self, cipher, key="", alphabet=alphabets.ENGLISH): + def __init__(self, cipher, key="", alphabet=al.ENGLISH): self.__key = key self.set_cipher(cipher) self.set_alphabet(alphabet) - def set_key(self, key): - self.__key = key - - def set_alphabet(self, alphabet=alphabets.ENGLISH): - if hasattr(self.__cipher, 'get_fixed_alphabet'): - return - self.__alphabet = alphabet - self.mixedcase = False - - def get_alphabet(self): - return self.__alphabet - - def set_cipher(self, cipher): - self.__cipher = cipher - if not hasattr(self.__cipher, 'get_fixed_alphabet'): - return - alphabet = cipher.get_fixed_alphabet() + def __define_mixedcase(self, alphabet): # check upper case letters has_upper = False has_lower = False - if isinstance(alphabet, str): - for c in alphabet: + for letters in alphabet: + for c in letters: if c.isupper(): has_upper = True elif c.lower(): has_lower = True - else: - for letters in alphabet: - for c in letters: - if c.isupper(): - has_upper = True - elif c.lower(): - has_lower = True if has_upper and has_lower: self.__alphabet = alphabet @@ -55,6 +32,24 @@ def set_cipher(self, cipher): self.__alphabet = alphabet self.mixedcase = False + def set_key(self, key): + self.__key = key + + def set_alphabet(self, alphabet=al.ENGLISH): + if hasattr(self.__cipher, 'get_fixed_alphabet'): + return + self.__define_mixedcase(alphabet) + + def get_alphabet(self): + return self.__alphabet + + def set_cipher(self, cipher): + self.__cipher = cipher + if not hasattr(cipher, 'get_fixed_alphabet'): + return + alphabet = cipher.get_fixed_alphabet() + self.__define_mixedcase(alphabet) + # returns True if mixedcase in alphabet, False otherwise def has_mixedcase(self): return self.mixedcase From 6f18b7c315a91b2677fc6e6dec441821c77b4233 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 18 Jul 2021 19:06:20 +0200 Subject: [PATCH 13/33] Use Gronsfeld inside of Vigenere cipher - Refactor Gronsfeld - Update example of Gronfeld Difference between Vigenere and Gronsfeld is only the key representation --- examples/gronsfeld.py | 90 +++++++++++++++++++++++++++-------- secretpy/ciphers/gronsfeld.py | 34 +++++++------ secretpy/ciphers/vigenere.py | 22 ++++----- 3 files changed, 97 insertions(+), 49 deletions(-) diff --git a/examples/gronsfeld.py b/examples/gronsfeld.py index 7e32d2b..8a32fbe 100755 --- a/examples/gronsfeld.py +++ b/examples/gronsfeld.py @@ -1,16 +1,17 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Gronsfeld -from secretpy import alphabets +from secretpy import Gronsfeld, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -alphabet = alphabets.GERMAN -plaintext = u"thequickbrownfoxjumpsoverthelazydog" -key = (4, 7, 9) + +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" +key = (4, 17, 9) cipher = Gronsfeld() -print(plaintext) +print(plaintext) enc = cipher.encrypt(plaintext, key, alphabet) print(enc) dec = cipher.decrypt(enc, key, alphabet) @@ -18,23 +19,72 @@ ####################################################### -print("----------------------------------") -plaintext = u"attackatdawn" +def encdec(machine, plaintext): + print("--------------------------------------------------------------------") + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) + + key = (14, 2, 11) +cm0 = CryptMachine(cipher, key) -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) +cm = cm0 +cm.set_alphabet(al.ENGLISH) +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep=" ") +cm.set_key((1, 12, 7, 2)) +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) + +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) ''' -thequickbrownfoxjumpsoverthelazydog -xonuörgrkvvbrmxöqßqwösünväqisjßbmsn -thequickbrownfoxjumpsoverthelazydog ----------------------------------- -attackatdawn -oveoevovooyy -attackatdawn +schweißgequältvomödentextzürnttypografjakob +wtqävrdxnuhfpgasßghvwxvcxmhvaüxlysxäewseöxf +schweißgequältvomödentextzürnttypografjakob +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +wfzbvwcxpbqyonavcmsvnvccoeestdwytzncsozjglznztvssorfglh +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +utpuu qevje kkwuk genfd majmt amnfz nvi +thistextisdividedbyblocksoflength +-------------------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +J xvxf zvp-bxwjbnlv dthtboagse. Ajfel csq : ^,&@$~(*;?&#. Ajbf'z ku! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +-------------------------------------------------------------------- +Jj becomes Ii because we use ENGLISH_SQUARE_IJ! +Kv igdatgt Vq dfphwtr dg vem GOTSLTU_ZSVNYG_KV! +Ii becomes Ii because we use ENGLISH_SQUARE_II! +-------------------------------------------------------------------- +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text うえぶねばまに てるぼゅゃ をすをつろぢ どはにぇり おゐはしごよみ ざぼぎおは くすくょるめす ゑぺれざせ ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +-------------------------------------------------------------------- +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΙΟΡΖΊ ΊΧΖΥΡ ΠΒΊ ΔΎΝΝΠ Μ ΖΜΞΑΊΈΆΌΒ. (ΆΧΙΣΖΊΩ ΜΒΎΉΠΤ) +ΘΈΛΕΙ ΑΡΕΤΉ ΚΑΙ ΤΌΛΜΗ Η ΕΛΕΥΘΕΡΊΑ. (ΑΝΔΠΈΑΣ ΚΆΛΒΟΣ) ''' diff --git a/secretpy/ciphers/gronsfeld.py b/secretpy/ciphers/gronsfeld.py index f1104b0..0f7c465 100755 --- a/secretpy/ciphers/gronsfeld.py +++ b/secretpy/ciphers/gronsfeld.py @@ -1,5 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from itertools import cycle +from secretpy import alphabets as al class Gronsfeld: @@ -7,20 +9,22 @@ class Gronsfeld: The Gronsfeld Cipher """ - def __encDec(self, alphabet, key, text, isEncrypt): - ans = "" - for i in range(len(text)): - char = text[i] - keyi = key[i % len(key)] + def __crypt(self, alphabet, key, text, is_encrypt): + # prepare alphabet for substitution + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + # prepare key + key_indexes = (is_encrypt * i for i in key) + res = [] + for keyi, char in zip(cycle(key_indexes), text): try: - alphIndex = (alphabet.index(char) + isEncrypt * keyi) % len(alphabet) - except ValueError: + i = (indexes[char] + keyi) % len(alphabet) + res.append(alphabet[i][0]) + except KeyError: wrchar = char.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - ans += alphabet[alphIndex] - return ans + return "".join(res) - def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -29,14 +33,14 @@ def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: tuple of integers :type alphabet: string :return: text :rtype: string """ - return self.__encDec(alphabet, key, text, 1) + return self.__crypt(alphabet, key, text, 1) - def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -45,9 +49,9 @@ def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: tuple of integers :type alphabet: string :return: text :rtype: string """ - return self.__encDec(alphabet, key, text, -1) + return self.__crypt(alphabet, key, text, -1) diff --git a/secretpy/ciphers/vigenere.py b/secretpy/ciphers/vigenere.py index f2b54c7..c9747cb 100755 --- a/secretpy/ciphers/vigenere.py +++ b/secretpy/ciphers/vigenere.py @@ -1,28 +1,20 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from itertools import cycle from secretpy import alphabets as al +from .gronsfeld import Gronsfeld class Vigenere: """ The Vigenere Cipher """ + __gronsfeld = Gronsfeld() - def __crypt(self, alphabet, key, text, is_encrypt): + def __crypt(self, alphabet, key): # prepare alphabet for substitution indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} # prepare key - key_indexes = (is_encrypt * indexes[c] for c in key) - res = [] - for keyi, char in zip(cycle(key_indexes), text): - try: - i = (indexes[char] + keyi) % len(alphabet) - res.append(alphabet[i][0]) - except KeyError: - wrchar = char.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - return "".join(res) + return (indexes[c] for c in key) def encrypt(self, text, key, alphabet=al.ENGLISH): """ @@ -38,7 +30,8 @@ def encrypt(self, text, key, alphabet=al.ENGLISH): :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, 1) + new_key = self.__crypt(alphabet, key) + return self.__gronsfeld.encrypt(text, new_key, alphabet) def decrypt(self, text, key, alphabet=al.ENGLISH): """ @@ -54,4 +47,5 @@ def decrypt(self, text, key, alphabet=al.ENGLISH): :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, -1) + new_key = self.__crypt(alphabet, key) + return self.__gronsfeld.decrypt(text, new_key, alphabet) From e51a57db8e0e01c6c891d499bfb044f09db41b71 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 18 Jul 2021 22:26:24 +0200 Subject: [PATCH 14/33] Refactor SimpleSubstitution cipher - used dictionary to make fast substitution - support non-string alphabets --- examples/simplesubstitution.py | 92 ++++++++++++++++++++------ secretpy/ciphers/simplesubstitution.py | 46 ++++++------- 2 files changed, 92 insertions(+), 46 deletions(-) diff --git a/examples/simplesubstitution.py b/examples/simplesubstitution.py index 199784a..6b66eee 100755 --- a/examples/simplesubstitution.py +++ b/examples/simplesubstitution.py @@ -1,16 +1,16 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import SimpleSubstitution -from secretpy import alphabets +from secretpy import SimpleSubstitution, CryptMachine, alphabets as al +from secretpy.cmdecorators import Block, SaveAll -alphabet = alphabets.GERMAN -plaintext = u"thequickbrownfoxjumpsoverthelazydog" -key = u"dabcghijokzlmnpqrstuvfwxyäöeüß" cipher = SimpleSubstitution() -print(plaintext) +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" +key = u"fwxyäöeßüdabcglmnpqrstuvhjoikz" +print(plaintext) enc = cipher.encrypt(plaintext, key, alphabet) print(enc) dec = cipher.decrypt(enc, key, alphabet) @@ -18,24 +18,72 @@ ####################################################### -print("----------------------------------") -plaintext = u"thisisasecretmessage" -alphabet = alphabets.ENGLISH -key = u"dabcghijokzlmnpqrstuvfwxye" +def encdec(machine, plaintext): + print("--------------------------------------------------------------------") + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) -print(plaintext) -enc = cipher.encrypt(plaintext, key, alphabet) -print(enc) -dec = cipher.decrypt(enc, key, alphabet) -print(dec) + +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.ENGLISH) +cm.set_key("yzabchijkdeflmntuvwxopqrsg") +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep=")(") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +key = ( + "n", "g", "a", "b", "l", + "s", "t", "u", "v", "c", + "m", "o", "p", "q", "h", + "ij", "k", "w", "x", "y", + "r", "d", "e", "f", "z" +) +cm.set_key(key) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +alphabet = u"abcdABCDEfghijFGHIJ" +key = u"dABDFIJEfgCHabchijG" +cm.set_alphabet(alphabet) +cm.set_key(key) +plaintext = u"Text aBcdHijf" +encdec(cm, plaintext) ''' -thequickbrownfoxjumpsoverthelazydog -ujgrvobzaspwnhpxkvmqtpfgsujgldäycpi -thequickbrownfoxjumpsoverthelazydog ----------------------------------- -thisisasecretmessage -ujototdtgbsgumgttdig -thisisasecretmessage +schweißgequältvomödentextzürnttypografjakob +qxßuäüzeänsobrtlciyägrävrjkpgrrhmlepfödfalw +schweißgequältvomödentextzürnttypografjakob +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +kbnmxfnpcmnmyftjyzcxajyvyaxcvwkqkffvclnpcyffnhxjclivcyx +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +xjkwx-crxkw-bkpkb-cbzsz-fnaew-nhfcm-ixj +thistextisdividedbyblocksoflength +-------------------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +K fnpc mnm-yftjyzcx ajyvyaxcvw. Xjcwc yvc : ^,&@$~(*;?&#. Xjyx'w kx! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +-------------------------------------------------------------------- +Jj becomes Ii because we use ENGLISH_SQUARE_IJ! +Vv glaqolw Vv glanywl dl ywl LPTMVWU_WIYNKL_VV! +Ii becomes Ii because we use ENGLISH_SQUARE_II! +-------------------------------------------------------------------- +Text aBcdHijf +Text dIBDiabg +Text aBcdHijf ''' diff --git a/secretpy/ciphers/simplesubstitution.py b/secretpy/ciphers/simplesubstitution.py index 5c6dbee..a563d15 100755 --- a/secretpy/ciphers/simplesubstitution.py +++ b/secretpy/ciphers/simplesubstitution.py @@ -1,13 +1,23 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from secretpy import alphabets as al class SimpleSubstitution: """ The Simple Substitution Cipher """ + def __crypt(self, subst, text): + res = [] + for c in text: + try: + res.append(subst[c]) + except KeyError: + wrchar = c.encode('utf-8') + raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") + return "".join(res) - def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -16,24 +26,18 @@ def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: string :type alphabet: string :return: text :rtype: string """ if len(alphabet) != len(key): - return - res = [] - for c in text: - try: - k = key[alphabet.index(c)] - except ValueError: - wrchar = c.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - res.append(k) - return "".join(res) + raise Exception("Lengths of alphabet and key should be the same") + # prepare alphabet for substitution + subst = {a: k[0] for k, letters in zip(key, alphabet) for a in letters} + return self.__crypt(subst, text) - def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -42,19 +46,13 @@ def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: string :type alphabet: string :return: text :rtype: string """ if len(alphabet) != len(key): - return - res = [] - for c in text: - try: - k = alphabet[key.index(c)] - except ValueError: - wrchar = c.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - res.append(k) - return "".join(res) + raise Exception("Lengths of alphabet and key should be the same") + # prepare alphabet for substitution + subst = {k[0]: a[0] for k, a in zip(key, alphabet)} + return self.__crypt(subst, text) From c7ff12cac3c0c00beceea84622785c0df68b6df4 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 18 Jul 2021 23:20:30 +0200 Subject: [PATCH 15/33] Update Beaufort - created tuple for key --- secretpy/ciphers/beaufort.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/secretpy/ciphers/beaufort.py b/secretpy/ciphers/beaufort.py index bc87991..54397a7 100755 --- a/secretpy/ciphers/beaufort.py +++ b/secretpy/ciphers/beaufort.py @@ -12,20 +12,17 @@ class Beaufort: def __crypt(self, alphabet, key, text): # prepare alphabet for substitution - indeces = {c: i for i, letters in enumerate(alphabet) for c in letters} + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + # prepare key + key_indexes = (indexes[c] for c in key) res = [] - for k, t in zip(cycle(key), text): + for k, t in zip(cycle(key_indexes), text): try: - i = indeces[k] - except KeyError: - wrchar = k.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - try: - i -= indeces[t] + i = k - indexes[t] + res.append(alphabet[i][0]) except KeyError: wrchar = t.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - res.append(alphabet[i][0]) return "".join(res) def encrypt(self, text, key, alphabet=al.ENGLISH): From 597a343450f064df5614d788d5a4d9c0db5988fe Mon Sep 17 00:00:00 2001 From: tigertv Date: Mon, 19 Jul 2021 13:14:20 +0200 Subject: [PATCH 16/33] Support non-string alphabets in Porta cipher --- examples/porta.py | 63 ++++++++++++++++++++++++++------------- secretpy/ciphers/porta.py | 57 ++++++++++++++++------------------- 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/examples/porta.py b/examples/porta.py index 5d83bb7..0dd8608 100755 --- a/examples/porta.py +++ b/examples/porta.py @@ -1,12 +1,12 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from secretpy import Porta, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -from secretpy import Porta -from secretpy import alphabets -alphabet = alphabets.GERMAN -plaintext = u"thequickbrownfoxjumpsoverthelazydog" -key = u"dogs" +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" +key = u"schlüssel" cipher = Porta() print(plaintext) @@ -18,23 +18,46 @@ ####################################################### -print("----------------------------------") -plaintext = u"attackatdawn" -key = u"lemon" +def encdec(machine, plaintext): + print("--------------------------------------------------------------------") + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) + +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.ENGLISH) +cm.set_key("keys") +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=4, sep="::") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(u"かぎ") +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) + +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +cm.set_key(u"κλειδί") +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) ''' -thequickbrownfoxjumpsoverthelazydog -dßwheputrkrnßöroznpgcvdübmzüöwhatvy -thequickbrownfoxjumpsoverthelazydog ----------------------------------- -attackatdawn -seauvppaxtel -attackatdawn ''' diff --git a/secretpy/ciphers/porta.py b/secretpy/ciphers/porta.py index 10475fd..def66af 100755 --- a/secretpy/ciphers/porta.py +++ b/secretpy/ciphers/porta.py @@ -1,38 +1,15 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- - -from secretpy import alphabets +from itertools import cycle +from secretpy import alphabets as al class Porta: """ The Porta Cipher """ - def __encDec(self, alphabet, key, text): - ans = "" - for i, char in enumerate(text): - try: - keychari = alphabet.index(key[i % len(key)]) >> 1 - except ValueError: - wrchar = key[i % len(key)].encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - try: - textindex = alphabet.index(char) - except ValueError: - wrchar = char.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - half = len(alphabet) >> 1 - half_alphabet = None - if textindex < half: - half_alphabet = alphabet[half:] - alphIndex = (textindex + keychari) % half - else: - half_alphabet = alphabet[0:half] - alphIndex = (textindex - keychari) % half - ans += half_alphabet[alphIndex] - return ans - def encrypt(self, text, key, alphabet=alphabets.ENGLISH): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -41,14 +18,31 @@ def encrypt(self, text, key, alphabet=alphabets.ENGLISH): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: string :type alphabet: string :return: text :rtype: string """ - return self.__encDec(alphabet, key, text) + # prepare alphabet for substitution + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + # prepare key + key_indexes = (indexes[c] >> 1 for c in key) + half = len(alphabet) >> 1 + res = [] + for t, k in zip(text, cycle(key_indexes)): + try: + texti = indexes[t] + except ValueError: + wrchar = t.encode('utf-8') + raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") + if texti < half: + i = (texti + k) % half + half + else: + i = (texti - k) % half + res.append(alphabet[i][0]) + return u"".join(res) - def decrypt(self, text, key, alphabet=alphabets.ENGLISH): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -57,10 +51,9 @@ def decrypt(self, text, key, alphabet=alphabets.ENGLISH): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: string :type alphabet: string :return: text :rtype: string """ - - return self.__encDec(alphabet, key, text) + return self.encrypt(text, key, alphabet) From 14d889cba7403af43ca9605563e622f8d6f7edaf Mon Sep 17 00:00:00 2001 From: tigertv Date: Tue, 20 Jul 2021 01:07:25 +0200 Subject: [PATCH 17/33] Refactor Polybius and PolybiusSquare --- examples/polybius.py | 29 ++++++++++++++++++++---- secretpy/ciphers/polybius.py | 33 ++++++++------------------- secretpy/ciphers/polybius_square.py | 35 +++++++++++------------------ 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/examples/polybius.py b/examples/polybius.py index 21e0492..c655387 100755 --- a/examples/polybius.py +++ b/examples/polybius.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Polybius, CryptMachine, alphabets as alph +from secretpy import Polybius, CryptMachine, alphabets as al from secretpy.cmdecorators import SaveAll @@ -14,7 +14,8 @@ def encdec(machine, plaintext): print("----------------------------------") -cm = CryptMachine(Polybius()) +key = "mykey" +cm = CryptMachine(Polybius(), key) plaintext = u"Defend the east wall of the castle" encdec(cm, plaintext) @@ -34,6 +35,26 @@ def encdec(machine, plaintext): plaintext = "thisisasecretmessage" encdec(cm, plaintext) -cm.set_alphabet(alph.GREEK) -plaintext = u"ΠΙΝΑΚΑΣ" +cm.set_alphabet(al.GREEK) +cm.set_key(u"πινακασ") +plaintext = u"Ξεσκεπάζω την ψυχοφθόρα σας βδελυγμία." encdec(cm, plaintext) + +''' +Defend the east wall of the castle +22142314332243251414154243461532323423432514211542433214 +defendtheeastwallofthecastle +---------------------------------- +Defend the east wall of the castle +341433 143 1345 4211 41 424 4454512425253233542114422444542514 +defend the east wall of the castle +---------------------------------- +thisisasecretmessage +5421554455442444144241145411144444242314 +thisisasecretmessage +---------------------------------- +Ξεσκεπάζω την ψυχοφθόρα σας βδελυγμία. +422516152 511 213161513 213 565255435.434444514161446222425365223413514 +ξεσκεπάζω την ψυχοφθόρα σας βδελυγμία. +---------------------------------- +''' diff --git a/secretpy/ciphers/polybius.py b/secretpy/ciphers/polybius.py index ce8d769..be87358 100755 --- a/secretpy/ciphers/polybius.py +++ b/secretpy/ciphers/polybius.py @@ -1,8 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- - -import secretpy.alphabets as al +from itertools import starmap from .polybius_square import PolybiusSquare +import secretpy.alphabets as al class Polybius: @@ -10,7 +10,7 @@ class Polybius: The Polybius Cipher """ - def encrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): + def encrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): """ Encryption method @@ -25,15 +25,13 @@ def encrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): :rtype: string """ square = PolybiusSquare(alphabet, key) - header = list(map(str, range(1, square.get_columns() + 1))) res = [] - for t in text: - row, column = square.get_coordinates(t) - res.append(header[row]) - res.append(header[column]) + for row, column in map(square.get_coordinates, text): + res.append(str(row + 1)) + res.append(str(column + 1)) return "".join(res) - def decrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): + def decrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): """ Decryption method @@ -48,21 +46,8 @@ def decrypt(self, text, key="", alphabet=al.ENGLISH_SQUARE_IJ): :rtype: string """ square = PolybiusSquare(alphabet, key) - header = list(map(str, range(1, square.get_columns() + 1))) - res = [] - for i in range(1, len(text), 2): - try: - row = header.index(text[i - 1]) - except ValueError: - wrchar = text[i - 1].encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - try: - column = header.index(text[i]) - except ValueError: - wrchar = text[i].encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - res.append(square.get_char(row, column)) - return "".join(res) + it = iter(map(lambda t: int(t) - 1, text)) + return "".join(starmap(square.get_char, zip(it, it))) def get_crypt_alphabet(self): return al.DECIMAL diff --git a/secretpy/ciphers/polybius_square.py b/secretpy/ciphers/polybius_square.py index 85d986b..709aac8 100755 --- a/secretpy/ciphers/polybius_square.py +++ b/secretpy/ciphers/polybius_square.py @@ -11,33 +11,24 @@ class PolybiusSquare: PolybiusSquare. It's used by many classical ciphers """ - def __init__(self, alphabet, key=""): - keyi = [] + def __init__(self, alphabet=al.ENGLISH_SQUARE_IJ, key=None): + self.__side = int(math.ceil(math.sqrt(len(alphabet)))) + # prepare alphabet for substitution if key: - for char in key: - index = al.get_index_in_alphabet(char, alphabet) - keyi.append(index) + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} # remove duplicates - keyi = OrderedDict.fromkeys(keyi) - - alph_out = [alphabet[i] for i in keyi] + keyi = OrderedDict.fromkeys(indexes[char] for char in key) + self.__alphabet = [alphabet[i] for i in keyi] - for i in range(len(alphabet)): - if i not in keyi: - alph_out.append(alphabet[i]) - - self.__alphabet = alph_out - self.__side = int(math.ceil(math.sqrt(len(alphabet)))) + for i, a in enumerate(alphabet): + if i not in keyi: + self.__alphabet.append(a) + else: + self.__alphabet = alphabet + self.coords = {c: divmod(i, self.__side) for i, letters in enumerate(self.__alphabet) for c in letters} def get_coordinates(self, char): - for j in range(len(self.__alphabet)): - try: - self.__alphabet[j].index(char) - break - except ValueError: - pass - - return divmod(j, self.__side) + return self.coords[char] def get_char(self, row, column): return self.__alphabet[row * self.__side + column][0] From a31c40a710a9ad3a9d391db800080b82922c5328 Mon Sep 17 00:00:00 2001 From: tigertv Date: Thu, 22 Jul 2021 18:01:01 +0200 Subject: [PATCH 18/33] Refactor Myszkowski Transposition --- examples/myszkowski_transposition.py | 81 +++++++++++++-- secretpy/alphabets.py | 10 -- secretpy/ciphers/myszkowski_transposition.py | 102 +++++++++---------- tests/test_myszkowski_transposition.py | 7 +- 4 files changed, 122 insertions(+), 78 deletions(-) diff --git a/examples/myszkowski_transposition.py b/examples/myszkowski_transposition.py index 0d08a6f..c775dd7 100755 --- a/examples/myszkowski_transposition.py +++ b/examples/myszkowski_transposition.py @@ -1,30 +1,89 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import MyszkowskiTransposition, CryptMachine -from secretpy import alphabets +from secretpy import MyszkowskiTransposition, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll + +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" +key = u"schlüssel" + +cipher = MyszkowskiTransposition() +print(plaintext) + +enc = cipher.encrypt(plaintext, key, alphabet) +print(enc) +dec = cipher.decrypt(enc, key, alphabet) +print(dec) def encdec(machine, plaintext): + print("--------------------------------------------------------------------") print(plaintext) enc = machine.encrypt(plaintext) print(enc) print(machine.decrypt(enc)) - print("-------------------------------") -key = "tomato" -cm = CryptMachine(MyszkowskiTransposition(), key) +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.ENGLISH) +cm.set_key("tomatokey") +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep="-") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) -alphabet = alphabets.ENGLISH +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(u"かぎはにかぎ") +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) +cm = UpperCase(cm) +alphabet = al.GREEK cm.set_alphabet(alphabet) -plaintext = "wearediscoveredfleeatonce" +cm.set_key(u"κλειδί") +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) + +cm.set_key(u"kryptonyckeln") +cm.set_alphabet(al.SWEDISH) +plaintext = u"FAQ om Schweiz: Klöv du trång pjäxby?" encdec(cm, plaintext) ''' -wearediscoveredfleeatonce -rofoacdtedseeeacweivrlene -wearediscoveredfleeatonce -------------------------------- +schweißgequältvomödentextzürnttypografjakob +cuenfgmzghäntjwelötütrasißqvodxtrpoaobeteyk +schweißgequältvomödentextzürnttypografjakob +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +nahivevaclleohallroncsohdloptrrimatgitnleaeweefmtebtroa +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +svogt-doxes-iilnh-eddbk-ehtts-iyclt-ibf +thistextisdividedbyblocksoflength +-------------------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +V acei ncs-totreoha sslnpereer. Tielb ath : ^,&@$~(*;?&#. Aata'h th! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +-------------------------------------------------------------------- +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text いほとるわれつ むのまふあ きしもろへち をかそねう おゐけこさゆひ せにぬたら やてみはりよな ゑくえめす ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +-------------------------------------------------------------------- +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΙΚΜΥΑ ΣΣΛΤΌ ΛΊΈ ΒΕΉΛΕ Α ΑΟΑΑΗΘΝΚΘ. (ΡΙΗΕΔΆΈ ΕΤΕΡΡΛ) +ΘΈΛΕΙ ΑΡΕΤΉ ΚΑΙ ΤΌΛΜΗ Η ΕΛΕΥΘΕΡΊΑ. (ΑΝΔΡΈΑΣ ΚΆΛΒΟΣ) +-------------------------------------------------------------------- +FAQ om Schweiz: Klöv du trång pjäxby? +WNI PF ELGXZJC: KRÄS TO DAÖBM UQHVÅY? +FAQ OM SCHWEIZ: KLÖV DU TRÅNG PJÄXBY? ''' diff --git a/secretpy/alphabets.py b/secretpy/alphabets.py index c4d021a..e4cce51 100755 --- a/secretpy/alphabets.py +++ b/secretpy/alphabets.py @@ -2,16 +2,6 @@ # -*- encoding: utf-8 -*- -def get_index_in_alphabet(char, alphabet): - for j in range(len(alphabet)): - try: - alphabet[j].index(char) - break - except ValueError: - pass - return j - - BINARY = u"01" DECIMAL = u"0123456789" DOZENAL = u"0123456789ab" diff --git a/secretpy/ciphers/myszkowski_transposition.py b/secretpy/ciphers/myszkowski_transposition.py index fc25721..e627693 100755 --- a/secretpy/ciphers/myszkowski_transposition.py +++ b/secretpy/ciphers/myszkowski_transposition.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- - -from secretpy import alphabets +from itertools import repeat +from secretpy import alphabets as al class MyszkowskiTransposition: @@ -9,7 +9,8 @@ class MyszkowskiTransposition: The Myszkowski Transposition Cipher """ def __keycols(self, key, alphabet): - chars = [alphabets.get_index_in_alphabet(char, alphabet) for char in key] + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + chars = [indexes[char] for char in key] chars = sorted(enumerate(chars), key=lambda x: x[1]) cols = [[chars[0][0]]] @@ -20,49 +21,7 @@ def __keycols(self, key, alphabet): cols.append([chars[i][0]]) return cols - def __enc(self, alphabet, key, text): - ret = u"" - cols = self.__keycols(key, alphabet) - lines = len(text) // len(key) - if len(text) % len(key): - lines += 1 - - for col in cols: - for a in range(lines): - for i in col: - if i < len(text): - ret += text[i] - col = list(map(lambda x: x + len(key), col)) - return ret - - def __dec(self, alphabet, key, text): - ret = u"" - cols = self.__keycols(key, alphabet) - - lines = len(text) // len(key) - if len(text) % len(key): - lines += 1 - - m = [""] * len(key) - ci = 0 - for col in cols: - ccol = col - for line in range(lines): - for i, value in enumerate(ccol): - if value < len(text): - m[col[i]] += text[ci] - ci += 1 - ccol = list(map(lambda x: x + len(key), ccol)) - - for i in range(lines): - for j in m: - try: - ret += j[i] - except IndexError: - pass - return ret - - def encrypt(self, text, key, alphabet=None): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -76,10 +35,25 @@ def encrypt(self, text, key, alphabet=None): :return: text :rtype: string """ - alphabet = alphabet or alphabets.ENGLISH - return self.__enc(alphabet, key, text) + res = [] + keyorder = self.__keycols(key, alphabet) + for columns in keyorder: + if len(columns) == 1: + res.append(text[columns[0]::len(key)]) + else: + # use zip_longest in python3 + iterators = [iter(text[i::len(key)]) for i in columns] + it_count = len(iterators) + while it_count: + for i, it in enumerate(iterators): + try: + res.append(next(it)) + except StopIteration: + it_count -= 1 + iterators[i] = repeat('') + return u"".join(res) - def decrypt(self, text, key, alphabet=None): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -93,5 +67,31 @@ def decrypt(self, text, key, alphabet=None): :return: text :rtype: string """ - alphabet = alphabet or alphabets.ENGLISH - return self.__dec(alphabet, key, text) + cols = self.__keycols(key, alphabet) + + lines, rmd = divmod(len(text), len(key)) + lines += rmd > 0 + + columns = [[] for _ in range(len(key))] + texti = iter(text) + # fill columns + for col in cols: + ccol = col + for _ in range(lines): + for i, value in enumerate(ccol): + if value < len(text): + columns[col[i]].append(next(texti)) + ccol = [i + len(key) for i in ccol] + + # read result from columns + res = [] + iterators = [iter(column) for column in columns] + loop = True + while loop: + for it in iterators: + try: + res.append(next(it)) + except StopIteration: + loop = False + break + return u"".join(res) diff --git a/tests/test_myszkowski_transposition.py b/tests/test_myszkowski_transposition.py index 814f200..eaa84c5 100755 --- a/tests/test_myszkowski_transposition.py +++ b/tests/test_myszkowski_transposition.py @@ -10,27 +10,22 @@ class TestMyszkowskiTransposition(unittest.TestCase): alphabet = ( alphabets.ENGLISH, + alphabets.ENGLISH, ) key = ( u"tomato", u"german", - u"schlüssel", - u"clave", ) plaintext = ( u"wearediscoveredfleeatonce", u"defendtheeastwallofthecastlexx", - u"textnachtricht", - u"unmensaiedetexto", ) ciphertext = ( u"rofoacdtedseeeacweivrlene", u"nalcxehwttdttfseeleedsoaxfeahl", - u"111111111", - u"222222222222222", ) cipher = MyszkowskiTransposition() From 5a3454aea97d609412d0af8094ed1d33195a43bb Mon Sep 17 00:00:00 2001 From: tigertv Date: Thu, 22 Jul 2021 21:18:19 +0200 Subject: [PATCH 19/33] Refactor Vic cipher --- examples/vic.py | 16 ++++---- secretpy/ciphers/vic.py | 90 +++++++++++++++-------------------------- 2 files changed, 41 insertions(+), 65 deletions(-) diff --git a/examples/vic.py b/examples/vic.py index 34470e8..6d12f0b 100755 --- a/examples/vic.py +++ b/examples/vic.py @@ -1,34 +1,34 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Vic -from secretpy import CryptMachine +from secretpy import Vic, CryptMachine +from secretpy.cmdecorators import SaveAll def encdec(machine, plaintext): + print("----------------------------------") print(plaintext) enc = machine.encrypt(plaintext) print(enc) print(machine.decrypt(enc)) - print("----------------------------------") key = "0452" -cm = CryptMachine(Vic(), key) +cm = SaveAll(CryptMachine(Vic(), key)) alphabet = [ u"e", u"t", u"", u"a", u"o", u"n", u"", u"r", u"i", u"s", u"b", u"c", u"d", u"f", u"g", u"h", u"j", u"k", u"l", u"m", u"p", u"q", u"/", u"u", u"v", u"w", u"x", u"y", u"z", u".", ] -plaintext = u"attackatdawn" +plaintext = u"Attack at dawn!" cm.set_alphabet(alphabet) encdec(cm, plaintext) ''' Output: -attackatdawn -anwhrsanroaeer -attackatdawn ---------------------------------- +Attack at dawn! +Anwhrs an roae!er +Attack at dawn! ''' diff --git a/secretpy/ciphers/vic.py b/secretpy/ciphers/vic.py index 3369b09..f4d4aad 100755 --- a/secretpy/ciphers/vic.py +++ b/secretpy/ciphers/vic.py @@ -1,5 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from secretpy import alphabets as al +from itertools import cycle class Vic: @@ -7,56 +9,39 @@ class Vic: The Vic Cipher """ - def __find_index_in_alphabet(self, char, alphabet): - for j in range(len(alphabet)): - try: - alphabet[j].index(char) - break - except ValueError: - pass - return j - - def __encDec(self, alphabet, text, key, do_encrypt): + def __crypt(self, alphabet, text, key): columns = [] + subst = {} width = 10 - # define columns with null string + # prepare substitution from alphabet for i, value in enumerate(alphabet): if value == "": columns.append(i) - - # encode chars to numbers - code = "" - for char in text: - j = self.__find_index_in_alphabet(char, alphabet) - row = int(j / width) - if row > 0: - column = j % width - code += str(columns[row - 1]) + str(column) + elif i < width: + subst[value] = (i,) else: - code += str(j) + row, col = divmod(i, width) + subst[value] = (columns[row - 1], col) - enc = "" - if do_encrypt: - # addition by key - for i in range(0, len(code)): - enc += str((int(code[i]) + int(key[i % len(key)])) % 10) - else: - # subraction by key - for i in range(0, len(code)): - enc += str((int(code[i]) - int(key[i % len(key)])) % 10) + # encode chars to numbers + code = [] + for t in text: + code.extend(subst[t]) - # encode numbers to chars - enc2 = "" + res = [] row = 0 - for i in range(0, len(enc)): - if row == 0 and (int(enc[i]) in columns): - row = columns.index(int(enc[i])) + 1 + for c, k in zip(code, cycle(key)): + # apply the key + i = (c + k) % width + # encode numbers to chars + if row == 0 and (i in columns): + row = columns.index(i) + 1 else: - enc2 += alphabet[row * width + int(enc[i])][0] + res.append(alphabet[row * width + i][0]) row = 0 - return enc2 + return u"".join(res) - def encrypt(self, text, key=None, alphabet=None): + def encrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): """ Encryption method @@ -65,21 +50,16 @@ def encrypt(self, text, key=None, alphabet=None): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: number string :type alphabet: string :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__encDec(alphabet, text, key, True) + # prepare key + new_key = (int(i) for i in key) + return self.__crypt(alphabet, text, new_key) - def decrypt(self, text, key=None, alphabet=None): + def decrypt(self, text, key=None, alphabet=al.ENGLISH_SQUARE_IJ): """ Decryption method @@ -88,16 +68,12 @@ def decrypt(self, text, key=None, alphabet=None): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: number string :type alphabet: string :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u'ij', u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__encDec(alphabet, text, key, False) + width = 10 + # invert key + new_key = (width - int(i) for i in key) + return self.__crypt(alphabet, text, new_key) From cc074162693eab02b542f11ab78b588d84526f40 Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 23 Jul 2021 11:36:56 +0200 Subject: [PATCH 20/33] Refactor Gronsfeld We can replace mod operation in the loop by using minus indexing for lists --- secretpy/ciphers/gronsfeld.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/secretpy/ciphers/gronsfeld.py b/secretpy/ciphers/gronsfeld.py index 0f7c465..6236afa 100755 --- a/secretpy/ciphers/gronsfeld.py +++ b/secretpy/ciphers/gronsfeld.py @@ -9,15 +9,14 @@ class Gronsfeld: The Gronsfeld Cipher """ - def __crypt(self, alphabet, key, text, is_encrypt): + def __crypt(self, alphabet, key, text): # prepare alphabet for substitution indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} # prepare key - key_indexes = (is_encrypt * i for i in key) res = [] - for keyi, char in zip(cycle(key_indexes), text): + for keyi, char in zip(cycle(key), text): try: - i = (indexes[char] + keyi) % len(alphabet) + i = indexes[char] - keyi res.append(alphabet[i][0]) except KeyError: wrchar = char.encode('utf-8') @@ -38,7 +37,9 @@ def encrypt(self, text, key, alphabet=al.ENGLISH): :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, 1) + # sanitize and invert the key + new_key = (-i % len(alphabet) for i in key) + return self.__crypt(alphabet, new_key, text) def decrypt(self, text, key, alphabet=al.ENGLISH): """ @@ -54,4 +55,6 @@ def decrypt(self, text, key, alphabet=al.ENGLISH): :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, -1) + # sanitize the key + new_key = (i % len(alphabet) for i in key) + return self.__crypt(alphabet, new_key, text) From 12b8069188bb190e51126195f149401dc9555e1e Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 23 Jul 2021 18:21:45 +0200 Subject: [PATCH 21/33] Fix abstract decorator Add some functions to execute on the CryptMachine through decorators --- secretpy/cmdecorators/decorator.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/secretpy/cmdecorators/decorator.py b/secretpy/cmdecorators/decorator.py index 27588d6..297ab57 100755 --- a/secretpy/cmdecorators/decorator.py +++ b/secretpy/cmdecorators/decorator.py @@ -15,9 +15,18 @@ def set_key(self, key): def set_alphabet(self, alphabet=alphabets.ENGLISH): self._machine.set_alphabet(alphabet) + def get_alphabet(self): + return self._machine.get_alphabet() + + def get_crypt_alphabet(self): + return self._machine.get_crypt_alphabet() + def set_cipher(self, cipher): self._machine.set_cipher(cipher) + def has_mixedcase(self): + return self._machine.has_mixedcase() + def encrypt(self, text): pass From 678a335ce25ef7c391999d5f14ecb3112f102513 Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 23 Jul 2021 18:40:06 +0200 Subject: [PATCH 22/33] Refactor Bazeries cipher --- examples/bazeries.py | 40 ++++++++++++++---- secretpy/ciphers/bazeries.py | 81 +++++++++++++----------------------- tests/test_bazeries.py | 5 +-- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/examples/bazeries.py b/examples/bazeries.py index c2385ba..88d1093 100755 --- a/examples/bazeries.py +++ b/examples/bazeries.py @@ -1,34 +1,56 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Bazeries, CryptMachine, alphabets -from secretpy.cmdecorators import UpperCase +from secretpy import Bazeries, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, SaveAll def encdec(machine, plaintext): + print("=" * 80) print(plaintext) enc = machine.encrypt(plaintext) print(enc) dec = machine.decrypt(enc) print(dec) - print("----------------------------------") -alphabet = alphabets.ENGLISH_SQUARE_IJ - -key = (81257, u"eightyonethousandtwohundredfiftyseven") - cm = UpperCase(CryptMachine(Bazeries())) +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) -cm.set_alphabet(alphabet) +key = (81257, u"eightyonethousandtwohundredfiftyseven") cm.set_key(key) plaintext = u"Whoever has made a voyage up the Hudson" \ u" must remember the Kaatskill mountains" encdec(cm, plaintext) +cm = SaveAll(cm) +encdec(cm, plaintext) + +cm = UpperCase(SaveAll(CryptMachine(Bazeries(), key))) +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = u"The quick brown fox jumps over the lazy dog!" +encdec(cm, plaintext) + +cm.set_alphabet(al.GREEK_SQUARE) +cm.set_key((2358, u"κλειδί")) +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) + ''' +================================================================================ Whoever has made a voyage up the Hudson must remember the Kaatskill mountains DUMTMCDSENRTEMVEQXMOELCCRVXDMDKWXNNMUKRDKUMYNMBPRKEEPMGNGEKWXCRWB WHOEVERHASMADEAVOYAGEUPTHEHUDSONMUSTREMEMBERTHEKAATSKILLMOUNTAINS ----------------------------------- +================================================================================ +Whoever has made a voyage up the Hudson must remember the Kaatskill mountains +DUMTMCD SEN RTEM V EQXMOE LC CRV XDMDKW XNNM UKRDKUMY NMB PRKEEPMGN GEKWXCRWB +WHOEVER HAS MADE A VOYAGE UP THE HUDSON MUST REMEMBER THE KAATSKILL MOUNTAINS +================================================================================ +The quick brown fox jumps over the lazy dog! +PAB XHMDK YCUFC IWS TCRQN XBZE GMD KUML CVO! +THE QUICK BROWN FOX IUMPS OVER THE LAZY DOG! +================================================================================ +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΥΜΡΥΕ ΒΨΥΖΚ ΒΓΕ ΧΨΡΚΦ Υ ΒΔΥΕΚΡΖΥΜ. (ΦΣΚΥΖΠΝ ΚΕΚΣΧΑ) +ΘΕΛΕΙ ΑΡΕΤΗ ΚΑΙ ΤΟΛΜΗ Η ΕΛΕΥΘΕΡΙΑ. (ΑΝΔΡΕΑΞ ΚΑΛΒΟΞ) ''' diff --git a/secretpy/ciphers/bazeries.py b/secretpy/ciphers/bazeries.py index 7d69f17..04d5e84 100755 --- a/secretpy/ciphers/bazeries.py +++ b/secretpy/ciphers/bazeries.py @@ -1,7 +1,8 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- - +from secretpy import alphabets as al from .polybius_square import PolybiusSquare +from itertools import cycle class Bazeries: @@ -9,46 +10,38 @@ class Bazeries: The Bazeries Cipher """ - def __encDec(self, alphabet, text, key, isEncrypt=True): - square1 = PolybiusSquare(alphabet) - - # key is a number, make it a string - square2 = PolybiusSquare(alphabet, key[1]) - - # prepare text: group and reverse + def __crypt(self, alphabet, text, key, is_encrypt=True): + # prepare digit key temp = key[0] - groups = [] - while temp > 0: - rmd = temp % 10 - temp = int(temp / 10) - groups.append(rmd) - groups = groups[::-1] + digitkey = [] + while temp: + temp, rmd = divmod(temp, 10) + digitkey.append(rmd) + digitkey = digitkey[::-1] + # prepare text: reversion i = 0 - j = 0 - revtext = "" + revtext = [] + digitkey = cycle(digitkey) while i < len(text): - num = groups[j] - str1 = text[int(i):int(i + num)] - revtext += str1[::-1] + num = next(digitkey) + s = text[i:i + num] + revtext.append(s[::-1]) i += num - j += 1 - if j == len(groups): - j = 0 + revtext = u"".join(revtext) + + sq1 = PolybiusSquare(alphabet) + # key is a number, make it a string + sq2 = PolybiusSquare(alphabet, key[1]) + if is_encrypt: + sq1, sq2 = sq2, sq1 - # now we have reversed text and we encrypt - ret = "" - if isEncrypt: - for char in revtext: - coords = square1.get_coordinates(char) - ret += square2.get_char(coords[1], coords[0]) - else: - for char in revtext: - coords = square2.get_coordinates(char) - ret += square1.get_char(coords[1], coords[0]) - return ret + # prepare substitution from alphabet + subst = {c: sq1.get_char(*reversed(sq2.get_coordinates(c))) for letters in alphabet for c in letters} + # cryption + return u"".join(subst[t] for t in revtext) - def encrypt(self, text, key=None, alphabet=None): + def encrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ Encryption method @@ -62,16 +55,9 @@ def encrypt(self, text, key=None, alphabet=None): :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__encDec(alphabet, text, key, True) + return self.__crypt(alphabet, text, key, True) - def decrypt(self, text, key=None, alphabet=None): + def decrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ Decryption method @@ -85,11 +71,4 @@ def decrypt(self, text, key=None, alphabet=None): :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__encDec(alphabet, text, key, False) + return self.__crypt(alphabet, text, key, False) diff --git a/tests/test_bazeries.py b/tests/test_bazeries.py index aae0aeb..ce9dead 100755 --- a/tests/test_bazeries.py +++ b/tests/test_bazeries.py @@ -12,7 +12,7 @@ class TestBazeries(unittest.TestCase): alphabets.GERMAN_SQUARE, alphabets.SPANISH_SQUARE, alphabets.RUSSIAN_SQUARE, - alphabets.JAPANESE_HIRAGANA + # alphabets.JAPANESE_HIRAGANA ) key = ( @@ -48,8 +48,7 @@ def test_encrypt(self): def test_decrypt(self): for i, alphabet in enumerate(self.alphabet): - dec = self.cipher.decrypt(self.ciphertext[i], - self.key[i], alphabet) + dec = self.cipher.decrypt(self.ciphertext[i], self.key[i], alphabet) self.assertEqual(dec, self.plaintext[i]) From caa4b6aed154f3ecdf207f4d660fd2f9835413d1 Mon Sep 17 00:00:00 2001 From: tigertv Date: Fri, 23 Jul 2021 23:04:08 +0200 Subject: [PATCH 23/33] Optimise CaesarProgressive cipher Using inversion of key and minus index of alphabet to remove the mod operator in the loop --- secretpy/ciphers/caesar_progressive.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/secretpy/ciphers/caesar_progressive.py b/secretpy/ciphers/caesar_progressive.py index 2ea7fa6..c5d206c 100755 --- a/secretpy/ciphers/caesar_progressive.py +++ b/secretpy/ciphers/caesar_progressive.py @@ -10,16 +10,13 @@ class CaesarProgressive: The Caesar Progressive Cipher """ - def __crypt(self, alphabet, key, text, is_encrypt): - # key should be between 0 and len(alphabet) - key %= len(alphabet) + def __crypt(self, alphabet, key, text): # prepare alphabet for substitution subst = {c: i for i, letters in enumerate(alphabet) for c in letters} res = [] - ch = chain(range(key, len(alphabet)), range(key)) - for k, t in zip(cycle(ch), text): + for t, k in zip(text, cycle(key)): try: - i = (subst[t] + is_encrypt * k) % len(alphabet) + i = subst[t] - k except KeyError: wrchar = t.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") @@ -40,7 +37,9 @@ def encrypt(self, text, key=3, alphabet=al.ENGLISH): :return: encrypted text :rtype: string """ - return self.__crypt(alphabet, key, text, 1) + new_key = -key % len(alphabet) + new_key = chain(range(new_key, -1, -1), range(len(alphabet) - 1, new_key, -1)) + return self.__crypt(alphabet, new_key, text) def decrypt(self, text, key=3, alphabet=al.ENGLISH): """ @@ -56,4 +55,6 @@ def decrypt(self, text, key=3, alphabet=al.ENGLISH): :return: decrypted text :rtype: string """ - return self.__crypt(alphabet, key, text, -1) + new_key = key % len(alphabet) + new_key = chain(range(new_key, len(alphabet)), range(new_key)) + return self.__crypt(alphabet, new_key, text) From 9ea3e4cbe79b583ee9be90c15d178567dc967f03 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 24 Jul 2021 00:43:52 +0200 Subject: [PATCH 24/33] Fix SaveAll decorator Resulting text can be smaller than the source text, like it is in ThreeSquare cipher for decryption. For the reason, the uppercase's list is filtered. --- secretpy/cmdecorators/save_all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secretpy/cmdecorators/save_all.py b/secretpy/cmdecorators/save_all.py index 6778fcc..448a6b7 100755 --- a/secretpy/cmdecorators/save_all.py +++ b/secretpy/cmdecorators/save_all.py @@ -36,7 +36,7 @@ def __crypt(self, text, func, alphabet): # restore uppercase if not self._machine.has_mixedcase(): - for i in upcases: + for i in filter(lambda x: x < len(res), upcases): res[i] = res[i].upper() return "".join(res) From 2850aae65663ad69e29cd15a979c7ade3eec7109 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 24 Jul 2021 00:48:25 +0200 Subject: [PATCH 25/33] Refactor ThreeSquare cipher --- examples/three_square.py | 60 +++++++++++----- secretpy/ciphers/three_square.py | 114 ++++++++++++++----------------- 2 files changed, 93 insertions(+), 81 deletions(-) diff --git a/examples/three_square.py b/examples/three_square.py index 0d582f2..991c112 100755 --- a/examples/three_square.py +++ b/examples/three_square.py @@ -1,41 +1,67 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import ThreeSquare, CryptMachine, alphabets -from secretpy.cmdecorators import UpperCase +from secretpy import ThreeSquare, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, SaveAll, Block def encdec(machine, plaintext): + print("=" * 80) print(plaintext) enc = machine.encrypt(plaintext) print(enc) dec = machine.decrypt(enc) print(dec) - print("----------------------------------") -alphabet = alphabets.ENGLISH_SQUARE_OQ key = (u"example", u"keyword", u"third") cm = UpperCase(CryptMachine(ThreeSquare())) -cm.set_alphabet(alphabet) +cm.set_alphabet(al.ENGLISH_SQUARE_OQ) cm.set_key(key) -plaintext = u"Help me Obi wan Kenobi" +plaintext = u"The quick brown fox jumps over the lazy dog!" encdec(cm, plaintext) -alphabet = alphabets.ENGLISH_SQUARE_IJ -cm.set_alphabet(alphabet) +cm = SaveAll(cm) +encdec(cm, plaintext) + +cm = SaveAll(CryptMachine(ThreeSquare())) +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) key = (u"criptog", u"segurt", u"mars") cm.set_key(key) -plaintext = u"attack at dawn" +plaintext = u"Attack at dawns!!!" +encdec(cm, plaintext) + +cm.set_alphabet(al.GREEK_SQUARE) +key = (u"ίκλειδ", u"κλειδί", u"λειδίκ") +cm.set_key(key) +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) + +cm = UpperCase(Block(CryptMachine(ThreeSquare()))) +cm.set_alphabet(al.GREEK_SQUARE) +key = (u"ίκλειδ", u"κλειδί", u"λειδίκ") +cm.set_key(key) encdec(cm, plaintext) ''' -Help me Obi wan Kenobi -HJKNEMDHOHSACLYRISFJKUUKBEF -HELPMEOBIWANKENOBI ----------------------------------- -attack at dawn -QCTZABCSKXCATDAFWN -ATTACKATDAWN ----------------------------------- +================================================================================ +The quick brown fox jumps over the lazy dog! +TPGEDELYICAWBACHSYNNJOSUJJTYRPSUWHWYINTBJELCBTXYSFONMV +THEOUICKBROWNFOXJUMPSOVERTHELAZYDOGZ +================================================================================ +The quick brown fox jumps over the lazy dog! +TPJ LDONY IAAEX ARB SOUNH OSXS JVM RMMU EHW!OWNZBJEGCAKXKSFYUMU +THE OUICK BROWN FOX JUMPS OVER THE LAZY DOG!Z +================================================================================ +Attack at dawns!!! +Actuac vs ihctz!!!ddnwosuz +Attack at dawns!!!z +================================================================================ +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +Ινιχι ιιλβρ σετ τβκλβ θ κσωμεμογο. (Γκνιιπυ Οζεσθλ)ζπγξδεσξληςπλαβιβηνετψ +Θελει αρετη και τολμη η ελευθερια. (Ανδρεας Καλβος)ω +================================================================================ +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΠΝΚΛΙ ΕΙΛΒΒ ΣΙΗΤΓ ΜΛΓΑΚ ΣΔΜΕΚ ΟΗΩΓΙ ΣΙΚΠΥ ΜΖΕΠΥ ΛΒΠΓΘ ΤΕΡΞΛ ΖΕΠΕΘ ΒΚΚΗΞ ΞΤΨ +ΘΕΛΕΙΑΡΕΤΗΚΑΙΤΟΛΜΗΗΕΛΕΥΘΕΡΙΑΑΝΔΡΕΑΣΚΑΛΒΟΣΩ ''' diff --git a/secretpy/ciphers/three_square.py b/secretpy/ciphers/three_square.py index 4e48da8..c3eee8c 100755 --- a/secretpy/ciphers/three_square.py +++ b/secretpy/ciphers/three_square.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- - +from secretpy import alphabets as al from .polybius_square import PolybiusSquare import random @@ -10,50 +10,7 @@ class ThreeSquare: The Three Square Cipher """ - def __encDec(self, alphabet, text, key, isEncrypt): - square1 = PolybiusSquare(alphabet, key[0]) - square2 = PolybiusSquare(alphabet, key[1]) - square3 = PolybiusSquare(alphabet, key[2]) - - enc = u"" - if isEncrypt: - if len(text) % 2: - text += alphabet[-1][0] - - odd = text[1::2] - even = text[::2] - - for i in range(len(even)): - row1, column1 = square1.get_coordinates(even[i]) - row2, column2 = square2.get_coordinates(odd[i]) - - rows = square1.get_rows() - index = random.randrange(rows) - left = square1.get_char(index, column1) - - middle = square3.get_char(row1, column2) - - cols = square2.get_columns() - index = random.randrange(cols) - right = square2.get_char(row2, index) - - enc += left + middle + right - else: - trigrams = [] - i = 0 - while i < len(text): - trigrams.append(text[i:i + 3]) - i += 3 - - for trigram in trigrams: - col1 = square1.get_coordinates(trigram[0])[1] - row3, col3 = square3.get_coordinates(trigram[1]) - row2 = square2.get_coordinates(trigram[2])[0] - enc += square1.get_char(row3, col1) - enc += square2.get_char(row2, col3) - return enc - - def encrypt(self, text, key=None, alphabet=None): + def encrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ Encryption method @@ -62,21 +19,45 @@ def encrypt(self, text, key=None, alphabet=None): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: tuple of 3 strings :type alphabet: string :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__encDec(alphabet, text, key, True) + square1 = PolybiusSquare(alphabet, key[0]) + square2 = PolybiusSquare(alphabet, key[1]) + square3 = PolybiusSquare(alphabet, key[2]) - def decrypt(self, text, key=None, alphabet=None): + res = [] + it = iter(text) + rows = square1.get_rows() + cols = square2.get_columns() + while True: + try: + t = next(it) + except StopIteration: + break + row1, column1 = square1.get_coordinates(t) + try: + t = next(it) + except StopIteration: + t = alphabet[-1][0] + row2, column2 = square2.get_coordinates(t) + + i = random.randrange(rows) + left = square1.get_char(i, column1) + + middle = square3.get_char(row1, column2) + + i = random.randrange(cols) + right = square2.get_char(row2, i) + + res.append(left) + res.append(middle) + res.append(right) + return u"".join(res) + + def decrypt(self, text, key, alphabet=al.ENGLISH_SQUARE_IJ): """ Decryption method @@ -85,16 +66,21 @@ def decrypt(self, text, key=None, alphabet=None): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: tuple of 3 strings :type alphabet: string :return: text :rtype: string """ - alphabet = alphabet or [ - u"a", u"b", u"c", u"d", u"e", - u"f", u"g", u"h", u"ij", u"k", - u"l", u"m", u"n", u"o", u"p", - u"q", u"r", u"s", u"t", u"u", - u"v", u"w", u"x", u"y", u"z" - ] - return self.__encDec(alphabet, text, key, False) + square1 = PolybiusSquare(alphabet, key[0]) + square2 = PolybiusSquare(alphabet, key[1]) + square3 = PolybiusSquare(alphabet, key[2]) + + res = [] + it = iter(text) + for t0, t1, t2 in zip(it, it, it): + col1 = square1.get_coordinates(t0)[1] + row3, col3 = square3.get_coordinates(t1) + row2 = square2.get_coordinates(t2)[0] + res.append(square1.get_char(row3, col1)) + res.append(square2.get_char(row2, col3)) + return u"".join(res) From b2a16e2a207bbc1d712b03367b19b1f2496a7477 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 24 Jul 2021 12:37:31 +0200 Subject: [PATCH 26/33] Refactor Affine - Supported non-string alphabets(tuples of strings) - Precalculated alphabet substitution(calculation removed from the __crypt loop) --- examples/affine.py | 87 +++++++++++++++++++++++++++++--------- secretpy/ciphers/affine.py | 42 +++++++++--------- 2 files changed, 88 insertions(+), 41 deletions(-) diff --git a/examples/affine.py b/examples/affine.py index 7a2eae8..b5203e8 100755 --- a/examples/affine.py +++ b/examples/affine.py @@ -1,12 +1,13 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Affine, alphabets +from secretpy import Affine, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -alphabet = alphabets.GERMAN +alphabet = al.ENGLISH plaintext = u"thequickbrownfoxjumpsoverthelazydog" -key = [7, 8] +key = (7, 8) cipher = Affine() print(plaintext) @@ -16,26 +17,72 @@ dec = cipher.decrypt(enc, key, alphabet) print(dec) -####################################################### -print("----------------------------------") +def encdec(machine, plaintext): + print("=" * 80) + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) -key = [3, 4] -plaintext = u"attackatdawn" -# use default english alphabet -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.ENGLISH) +cm.set_key(key) +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=4, sep="/=/") +cm.set_alphabet(al.SWEDISH + al.DECIMAL) +plaintext = "This text is divided by blocks of length 4!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) + +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) -""" +''' thequickbrownfoxjumpsoverthelazydog -vögaüewsphqmjnqtlücxoqfghvögzidäßqu +lfkqsmwapxcgvrcntsojeczkxlfkhibudcy thequickbrownfoxjumpsoverthelazydog ----------------------------------- -attackatdawn -ejjekiejnesr -attackatdawn -""" +================================================================================ +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +mdcvlhczkvcvihjfipklwfixiwlkxemgmhhxkoczkihhcrlfkoyxkil +idontlovenonalphabetcharactersiwillremoveallofthemgreat +================================================================================ +This text is divided by blocks of length 4! +yszr/=/y7ny/=/zr0z/=/9z07/=/0pup/=/höwa/=/röeh/=/7vly/=/sf +thistextisdividedbyblocksoflength4 +================================================================================ +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +Z hö97 vöv-ih6sip7y wsikiwy7kr. Ys7r7 ik7 : ^,&@$~(*;?&#. Ysiy'r zy! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +================================================================================ +Jj becomes Ii because we use ENGLISH_SQUARE_IJ! +Pp qmxzlmc Pp qmxircm fm rcm MSADPCH_CORIVM_PP! +Ii becomes Ii because we use ENGLISH_SQUARE_II! +================================================================================ +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text さじやづぐかも ねあのくな てへよぢごる ばびたをつ ずゐぺにむべげ りぁゃとぷ けぬぱまどざほ ゑろひめぴ ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +================================================================================ +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΛΟΘΙΡ ΗΦΙΝΖ ΓΗΡ ΝΚΘΞΑ Α ΙΘΙΣΛΙΦΧΗ. (ΗΤΔΦΟΗΉ ΓΜΘΣΈΉ) +ΘΈΛΕΙ ΑΡΕΤΉ ΚΑΙ ΤΌΛΜΗ Η ΕΛΕΒΘΕΡΊΑ. (ΑΝΔΡΈΑΣ ΚΆΛΒΟΣ) +''' diff --git a/secretpy/ciphers/affine.py b/secretpy/ciphers/affine.py index 303f7bd..a51f319 100755 --- a/secretpy/ciphers/affine.py +++ b/secretpy/ciphers/affine.py @@ -1,4 +1,5 @@ #!/usr/bin/python +from secretpy import alphabets as al class Affine: @@ -6,31 +7,23 @@ class Affine: The Affine Cipher """ - def __crypt(self, alphabet, key, text, is_encrypt): - a = key[0] - b = key[1] + def __crypt(self, subst, text): res = [] - a_inverse = self.__get_inverse(a, alphabet) try: - for char in text: - if is_encrypt == 1: - a_index = (alphabet.index(char) * a + b) % len(alphabet) - else: - a_index = (a_inverse * (alphabet.index(char) - b)) % len(alphabet) - enc = alphabet[a_index] - res.append(enc) - except ValueError: - wrchar = char.encode('utf-8') + for t in text: + res.append(subst[t]) + except KeyError: + wrchar = t.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") return "".join(res) def __get_inverse(self, a, alphabet): for i in range(1, len(alphabet)): - if ((int(a) * int(i)) % int(len(alphabet))) == 1: + if (a * i) % len(alphabet) == 1: return i - return 0 + return 1 - def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -39,14 +32,17 @@ def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: tuple of 2 integers :type alphabet: string :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, 1) + a = int(key[0]) + b = int(key[1]) + subst = {c: alphabet[(i * a + b) % len(alphabet)][0] for i, letters in enumerate(alphabet) for c in letters} + return self.__crypt(subst, text) - def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -55,9 +51,13 @@ def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer + :type key: tuple of 2 integers :type alphabet: string :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, -1) + a = int(key[0]) + b = int(key[1]) + a = self.__get_inverse(a, alphabet) + subst = {c: alphabet[(a * (i - b)) % len(alphabet)][0] for i, letters in enumerate(alphabet) for c in letters} + return self.__crypt(subst, text) From 221f58d36a16e864099356cfd22e7bd7c21f0a95 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 24 Jul 2021 14:26:15 +0200 Subject: [PATCH 27/33] Refactor Atbash cipher - Support non-string alphabets (tuples of strings) - Precalculated substitution of alphabet --- examples/atbash.py | 37 ++++++++++++++++++++++++++++++------- secretpy/ciphers/atbash.py | 27 ++++++++++++++------------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/examples/atbash.py b/examples/atbash.py index 15f762f..f30026b 100755 --- a/examples/atbash.py +++ b/examples/atbash.py @@ -2,20 +2,19 @@ # -*- encoding: utf-8 -*- from secretpy import Atbash, CryptMachine, alphabets -import secretpy.cmdecorators as md +from secretpy.cmdecorators import UpperCase, SaveAll def encdec(machine, plaintext): + print("-" * 80) print(plaintext) enc = machine.encrypt(plaintext) print(enc) dec = machine.decrypt(enc) print(dec) - print("----------------------------------") -cm = CryptMachine(Atbash()) -cm = md.UpperCase(cm) +cm = UpperCase(CryptMachine(Atbash())) plaintext = u"attackatdawn" encdec(cm, plaintext) @@ -24,13 +23,37 @@ def encdec(machine, plaintext): cm.set_alphabet(alphabets.HEBREW) encdec(cm, plaintext) -plaintext = u"The Fox jumps in Zoo too Achtung minen" +cm = SaveAll(cm) +plaintext = u"The quick brown fox jumps over the lazy dog." cm.set_alphabet(alphabets.GERMAN) encdec(cm, plaintext) -plaintext = u"Achtung Minen" +plaintext = u"Achtung Minen!!!" encdec(cm, plaintext) cm.set_alphabet(alphabets.ARABIC) -plaintext = u"قط" +plaintext = u"حريتي : أن أكون كما لا يريدون لي أن أكون" encdec(cm, plaintext) + +''' +-------------------------------------------------------------------------------- +attackatdawn +ZGGZXPZGWZDM +ATTACKATDAWN +-------------------------------------------------------------------------------- +במקום +שלדץם +במקום +-------------------------------------------------------------------------------- +The quick brown fox jumps over the lazy dog. +KWZ NJVÖT ÜMPHQ YPG UJROL PIZM KWZ SßEF ÄPX. +THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. +-------------------------------------------------------------------------------- +Achtung Minen!!! +ßÖWKJQX RVQZQ!!! +ACHTUNG MINEN!!! +-------------------------------------------------------------------------------- +حريتي : أن أكون كما لا يريدون لي أن أكون +شطقزق : غس غصثس صعا فا قطقذثس فق غس غصثس +حريتي : أن أكون كما لا يريدون لي أن أكون +''' diff --git a/secretpy/ciphers/atbash.py b/secretpy/ciphers/atbash.py index f742d21..18b0236 100755 --- a/secretpy/ciphers/atbash.py +++ b/secretpy/ciphers/atbash.py @@ -1,4 +1,5 @@ #!/usr/bin/python +from secretpy import alphabets as al class Atbash: @@ -7,43 +8,43 @@ class Atbash: """ def __crypt(self, alphabet, text): + subst = {c: alphabet[len(alphabet) - i - 1][0] for i, letters in enumerate(alphabet) for c in letters} res = [] - for char in text: - try: - alphIndex = len(alphabet) - (alphabet.index(char)) - 1 - except ValueError: - wrchar = char.encode('utf-8') - raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - res.append(alphabet[alphIndex]) + try: + for t in text: + res.append(subst[t]) + except ValueError: + wrchar = t.encode('utf-8') + raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") return "".join(res) - def encrypt(self, text, key=None, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key=None, alphabet=al.ENGLISH): """ Encryption method :param text: Text to encrypt - :param key: Encryption key + :param key: is not used :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string :type key: integer - :type alphabet: string + :type alphabet: string or tuple of strings :return: text :rtype: string """ return self.__crypt(alphabet, text) - def decrypt(self, text, key=None, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key=None, alphabet=al.ENGLISH): """ Decryption method :param text: Text to decrypt - :param key: Decryption key + :param key: is not used :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string :type key: integer - :type alphabet: string + :type alphabet: string or tuple of strings :return: text :rtype: string """ From 0502887f66863cc6fe6851add28a09f8de91f153 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 24 Jul 2021 15:38:25 +0200 Subject: [PATCH 28/33] Refactor AutoKey cipher - Precalculated indexes - Supported non-string alphabets(tuples of string) --- examples/autokey.py | 79 ++++++++++++++++++++++++++++++------- secretpy/ciphers/autokey.py | 40 ++++++++++--------- 2 files changed, 85 insertions(+), 34 deletions(-) diff --git a/examples/autokey.py b/examples/autokey.py index 69bf504..e6185e8 100755 --- a/examples/autokey.py +++ b/examples/autokey.py @@ -1,10 +1,11 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Autokey, alphabets +from secretpy import Autokey, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -alphabet = alphabets.GERMAN +alphabet = al.GERMAN plaintext = u"thequickbrownfoxjumpsoverthelazydog" key = "queenly" @@ -16,25 +17,73 @@ dec = cipher.decrypt(enc, key, alphabet) print(dec) -####################################################### -print("----------------------------------") +def encdec(machine, plaintext): + print("--------------------------------------------------------------------") + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) -plaintext = u"attackatdawn" -# use default english alphabet -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.ENGLISH + al.DECIMAL) +cm.set_key("keys") +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep="-") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(u"かぎ") +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) + +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +cm.set_key(u"κλειδί") +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) ''' thequickbrownfoxjumpsoverthelazydog föiudtäßivamvhyyäeeüxüonhbwwzvßlwvk thequickbrownfoxjumpsoverthelazydog ----------------------------------- -attackatdawn -qnxepvytwtwp -attackatdawn +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +shc51o28xy28ey3uamt0cieacjtvru10z3tdmxzcimz6sf4ssrzyimz +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +3l6ac-l5b1w-0130g-myj1f-op0l3-2hvw1-l4li +thistextisdividedbyblocksoflength5 +-------------------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +S pcdm y28-ey3uamt0 cieacjtvru. Clvax hvw : ^,&@$~(*;?&#. Xhrx'b pt! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +-------------------------------------------------------------------- +Jj becomes Ii because we use ENGLISH_SQUARE_IJ! +Sn zwlwniu Wu fwlivwg wy mwa IGYPNEO_CYMHIU_CI! +Ii becomes Ii because we use ENGLISH_SQUARE_II! +-------------------------------------------------------------------- +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text きうひつけえょ をすらぺだ むぁぽだぷほ すむよたし るゐざきびりよ わじすばぬ えへきありひぁ ゑじぇもあ ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +-------------------------------------------------------------------- +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΣΠΌΝΜ ΊΏΙΈΛ ΤΑΑ ΨΙΣΧΗ Ό ΨΆΌΗΟΚΎΎΕ. (ΥΎΉΘΟΑΣ ΨΕΓΗΟΛ) +ΉΈΛΕΙ ΑΣΕΤΉ ΚΑΘ ΤΌΚΜΗ Ή ΕΛΈΥΘΔΡΊΏ. (ΑΝΕΡΈΆΣ ΚΑΛΒΞΤ) ''' diff --git a/secretpy/ciphers/autokey.py b/secretpy/ciphers/autokey.py index 654f15b..daef3fc 100755 --- a/secretpy/ciphers/autokey.py +++ b/secretpy/ciphers/autokey.py @@ -1,5 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from secretpy import alphabets as al +from itertools import chain class Autokey: @@ -8,31 +10,31 @@ class Autokey: """ def __crypt(self, alphabet, key, text, is_encrypt): + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} res = [] - for i, t in enumerate(text): + + if is_encrypt == 1: + new_key = chain(key, text) + else: + new_key = chain(key, res) + + for t in text: + k = next(new_key) try: - a_index = alphabet.index(t) + i = indexes[t] except ValueError: wrchar = t.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - if i < len(key): - k = key[i] - else: - if is_encrypt == 1: - k = text[i - len(key)] - else: - k = res[i - len(key)] try: - a_index += is_encrypt * alphabet.index(k) + i += is_encrypt * indexes[k] except ValueError: wrchar = k.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - a_index = a_index % len(alphabet) - enc = alphabet[a_index] - res.append(enc) + i = i % len(alphabet) + res.append(alphabet[i][0]) return "".join(res) - def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -41,14 +43,14 @@ def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer - :type alphabet: string + :type key: string + :type alphabet: string or tuple of strings :return: text :rtype: string """ return self.__crypt(alphabet, key, text, 1) - def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -57,8 +59,8 @@ def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :param alphabet: Alphabet which will be used, if there is no a value, English is used :type text: string - :type key: integer - :type alphabet: string + :type key: string + :type alphabet: string or tuple of strings :return: text :rtype: string """ From 86d714c04b9c748dd984f7c795366d8210a0f1c3 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sat, 24 Jul 2021 19:07:30 +0200 Subject: [PATCH 29/33] Support non-string alphabets in Keyword cipher --- examples/keyword-ex.py | 83 +++++++++++++++++++++++++++++++------ secretpy/ciphers/keyword.py | 37 +++++++++-------- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/examples/keyword-ex.py b/examples/keyword-ex.py index 9283720..da1a647 100755 --- a/examples/keyword-ex.py +++ b/examples/keyword-ex.py @@ -1,10 +1,10 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- +from secretpy import Keyword, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -from secretpy import Keyword, alphabets - -alphabet = alphabets.GERMAN +alphabet = al.GERMAN plaintext = u"thequickbrownfoxjumpsoverthelazydog" key = "queenly" @@ -16,14 +16,73 @@ dec = cipher.decrypt(enc, key, alphabet) print(dec) -print("----------------------------------") -plaintext = u"thisisasecretmessage" -key = "keyword" +def encdec(machine, plaintext): + print("--------------------------------------------------------------------") + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) -# use default english alphabet -print(plaintext) -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) + +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm.set_alphabet(al.DECIMAL + al.ENGLISH) +cm.set_key("manykeys") +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = UpperCase(Block(cm, length=5, sep="-")) +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "Jj becomes Ii because we use ENGLISH_SQUARE_IJ!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(u"かぎ") +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" +encdec(cm, plaintext) + +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +cm.set_key(u"κλειδί") +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) + +''' +thequickbrownfoxjumpsoverthelazydog +rblmscefuojviyjwdshkpjtlorblgqzxnja +thequickbrownfoxjumpsoverthelazydog +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +c6jirgju7iji3glb347r5b3p35r7pqcvcggp7hju73ggj8rb7h9p73r +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +RBCQR-7WRCQ-6CUC6-764X4-GJ5FQ-J8G7I-9RBE +THISTEXTISDIVIDEDBYBLOCKSOFLENGTH5 +-------------------------------------------------------------------- +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +C gju7 iji-3glb347r 5b3p35r7pq. Rb7q7 3p7 : ^,&@$~(*;?&#. Rb3r'q cr! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +-------------------------------------------------------------------- +Jj becomes Ii because we use ENGLISH_SQUARE_IJ! +Cc aknigkq Cc aknmtqk vk tqk KHSFCQB_QOTMPK_CC! +Ii becomes Ii because we use ENGLISH_SQUARE_II! +-------------------------------------------------------------------- +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text ぎろはにほへと ちりぬるを わえよたれそ つねならむ あゐのうきやま くふけいて かさおゆめみし ゑひもせす ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +-------------------------------------------------------------------- +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΈΑΘΊΖ ΚΡΊΤΓ ΉΚΖ ΤΌΘΜΒ Β ΊΘΊΥΈΊΡΗΚ. (ΚΝΔΡΑΚΣ ΉΛΘΕΟΣ) +ΘΈΛΕΙ ΑΡΕΤΉ ΚΑΙ ΤΌΛΜΗ Η ΕΛΕΥΘΕΡΊΑ. (ΑΝΔΡΈΑΣ ΚΆΛΒΟΣ) +''' diff --git a/secretpy/ciphers/keyword.py b/secretpy/ciphers/keyword.py index 8cb3c91..75f4f6b 100755 --- a/secretpy/ciphers/keyword.py +++ b/secretpy/ciphers/keyword.py @@ -1,6 +1,7 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- from collections import OrderedDict +from secretpy import alphabets as al class Keyword: @@ -9,27 +10,29 @@ class Keyword: """ def __crypt(self, alphabet, key, text, is_encrypt): - # remove repeats of letters in the key - newkey = "".join(OrderedDict.fromkeys(key)) - # create the substitution string - longkey = "".join(OrderedDict.fromkeys(newkey + "".join(alphabet))) + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + # remove duplicates + keyi = OrderedDict.fromkeys(indexes[char] for char in key) + new_key = [alphabet[i] for i in keyi] + for i, a in enumerate(alphabet): + if i not in keyi: + new_key.append(a[0]) + + if is_encrypt: + subst = {c: new_key[i] for c, i in indexes.items()} + else: + subst = {c: alphabet[i][0] for i, letters in enumerate(new_key) for c in letters} # do encryption res = [] - for i, t in enumerate(text): + for t in text: try: - if is_encrypt == 1: - index = alphabet.index(t) - enc = longkey[index] - else: - index = longkey.index(t) - enc = alphabet[index] - except ValueError: + res.append(subst[t]) + except KeyError: wrchar = t.encode('utf-8') raise Exception("Can't find char '" + wrchar + "' of text in alphabet!") - res.append(enc) return "".join(res) - def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def encrypt(self, text, key, alphabet=al.ENGLISH): """ Encryption method @@ -43,9 +46,9 @@ def encrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, 1) + return self.__crypt(alphabet, key, text, True) - def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): + def decrypt(self, text, key, alphabet=al.ENGLISH): """ Decryption method @@ -59,4 +62,4 @@ def decrypt(self, text, key, alphabet=u"abcdefghijklmnopqrstuvwxyz"): :return: text :rtype: string """ - return self.__crypt(alphabet, key, text, -1) + return self.__crypt(alphabet, key, text, False) From 6417b10018351ddd0a2ffab89a360ffbb8b82bae Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 25 Jul 2021 01:20:06 +0200 Subject: [PATCH 30/33] Refactor Scytale cipher --- examples/scytale.py | 64 +++++++++++++++++++++---------------- secretpy/ciphers/scytale.py | 15 +++++---- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/examples/scytale.py b/examples/scytale.py index 7c3b410..71a6178 100755 --- a/examples/scytale.py +++ b/examples/scytale.py @@ -1,11 +1,11 @@ #!/usr/bin/python # -*- encoding: utf-8 -*- -from secretpy import Scytale, CryptMachine, alphabets -from secretpy.cmdecorators import SaveAll +from secretpy import Scytale, CryptMachine, alphabets as al +from secretpy.cmdecorators import UpperCase, Block, SaveAll -alphabet = alphabets.GERMAN +alphabet = al.GERMAN plaintext = u"thequickbrownfoxjumpsoverthelazydog" key = 3 cipher = Scytale() @@ -16,17 +16,6 @@ dec = cipher.decrypt(enc, key, alphabet) print(dec) -print('=====================================') - -print(plaintext) -# use default english alphabet -enc = cipher.encrypt(plaintext, key) -print(enc) -dec = cipher.decrypt(enc, key) -print(dec) - -# using cryptmachine - def encdec(machine, plaintext): print("--------------------------------------------------------------------") @@ -37,33 +26,52 @@ def encdec(machine, plaintext): cm0 = CryptMachine(cipher, key) -cm0.set_alphabet(alphabet) +cm0.set_alphabet(al.ENGLISH + al.DECIMAL) + +cm = cm0 +plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" +encdec(cm, plaintext) + +cm = UpperCase(Block(cm, length=5, sep="-")) +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) -plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" encdec(cm, plaintext) -plaintext = "I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great!" -cm = cm0 +cm.set_alphabet(al.JAPANESE_HIRAGANA) +plaintext = u"text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす !" encdec(cm, plaintext) -''' -Output: +cm = UpperCase(cm) +alphabet = al.GREEK +cm.set_alphabet(alphabet) +plaintext = u"Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)" +encdec(cm, plaintext) +''' thequickbrownfoxjumpsoverthelazydog tqcrnxmorezohukofjpvtlygeibwousehad thequickbrownfoxjumpsoverthelazydog -===================================== -thequickbrownfoxjumpsoverthelazydog -tqcrnxmorezohukofjpvtlygeibwousehad -thequickbrownfoxjumpsoverthelazydog +-------------------------------------------------------------------- +I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! +inonahehaeilevlfertdtvolatacrwlmeltmeolenpbcrtsiroaohga +idontlovenonalphabetcharactersiwillremoveallofthemgreat +-------------------------------------------------------------------- +This text is divided by blocks of length 5! +TSXSV-EYOSL-G5HTT-DIDBC-OETIE-IIDBL-KFNH +THISTEXTISDIVIDEDBYBLOCKSOFLENGTH5 -------------------------------------------------------------------- I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! I vola tac-rheeaile npbcrtseat. Ttona heh : ^,&@$~(*;?&#. Aets'r hs! I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! -------------------------------------------------------------------- -I don't love non-alphabet characters. I will remove all of them: ^,&@$~(*;?&#. Great! -inonahehaeilevlfertdtvolatacrwlmeltmeolenpbcrtsiroaohga -idontlovenonalphabetcharactersiwillremoveallofthemgreat - +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +text いにとぬわたつ らのやふて きみもろほち るかれねむ おゐまこあゆし せはへりを よそなうくけえ ゑさめひす ! +text いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす ! +-------------------------------------------------------------------- +Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος) +ΘΕΡΉΙ ΛΗΕΕΑ ΔΑΆ ΟΈΙΕΚ Τ ΜΕΥΡΑΡΣΛΣ. (ΛΑΤΑΌΗΛ ΘΊΝΈΚΒ) +ΘΈΛΕΙ ΑΡΕΤΉ ΚΑΙ ΤΌΛΜΗ Η ΕΛΕΥΘΕΡΊΑ. (ΑΝΔΡΈΑΣ ΚΆΛΒΟΣ) ''' diff --git a/secretpy/ciphers/scytale.py b/secretpy/ciphers/scytale.py index 57f0108..8f43d40 100644 --- a/secretpy/ciphers/scytale.py +++ b/secretpy/ciphers/scytale.py @@ -34,11 +34,12 @@ def decrypt(self, text, key, alphabet=None): :return: decrypted text :rtype: string """ - full_rows, rmd = len(text) // key, len(text) % key + full_rows, rmd = divmod(len(text), key) rows = full_rows + (rmd > 0) - index = rows * rmd - res = [text[i:index:rows] for i in range(rows)] - add_res = [res[i] + text[index + i::full_rows] for i in range(full_rows)] - if rmd: - add_res.append(res[-1]) - return "".join(add_res) + middle = rows * rmd + res = [] + for i in range(full_rows): + res.append(text[i:middle:rows]) + res.append(text[middle + i::full_rows]) + res.append(text[full_rows:middle:rows]) + return "".join(res) From d8acbc3bc63038f7fe37bd5c5b766d0dfe140846 Mon Sep 17 00:00:00 2001 From: tigertv Date: Sun, 25 Jul 2021 02:38:45 +0200 Subject: [PATCH 31/33] Support non-string alphabets in ColumnarTransposition --- examples/columnar_transposition.py | 44 +++++++++++++--------- secretpy/ciphers/columnar_transposition.py | 5 ++- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/examples/columnar_transposition.py b/examples/columnar_transposition.py index 05e251e..d950f40 100755 --- a/examples/columnar_transposition.py +++ b/examples/columnar_transposition.py @@ -6,24 +6,26 @@ cipher = ColumnarTransposition() -key = "cargo" -plaintext = "attackatdawn" +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" +key = u"schlüssel" print(plaintext) -enc = cipher.encrypt(plaintext, key) +enc = cipher.encrypt(plaintext, key, alphabet) print(enc) -print(cipher.decrypt(enc, key)) -print('========================================================================================') +dec = cipher.decrypt(enc, key, alphabet) +print(dec) def encdec(machine, plaintext): + print("=" * 80) print(plaintext) enc = machine.encrypt(plaintext) print(enc) print(machine.decrypt(enc)) - print("-----------------------------------------------------------") +key = "manykeys" cm0 = CryptMachine(cipher, key) cm = cm0 @@ -44,25 +46,33 @@ def encdec(machine, plaintext): plaintext = u"text あい だやぎへぐゆぢ" encdec(cm, plaintext) +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +cm.set_key(u"keyj") +plaintext = "ENGLISH_SQUARE_IJ doesn't change Ii to Jj because it's a transposition cipher!" +encdec(cm, plaintext) + ''' -attackatdawn -tanakwadcatt -attackatdawn -======================================================================================== +schweißgequältvomödentextzürnttypografjakob +cuenfgmzghäntjwlttaeöürsqdraivxpoßotobeteyk +schweißgequältvomödentextzürnttypografjakob +================================================================================ I don't love non-alphabet characters and uppercase. I will remove all of them: ^,&@$~(*;?&#. -donahtneelvomilohccapslolenelerrucweattnptaspaimlhovabaedriref +dnbcuemfllhsrlamtacreieeieaadseoooetpiotvhrnarlnntepwvhopaacll idontlovenonalphabetcharactersanduppercaseiwillremoveallofthem ------------------------------------------------------------ +================================================================================ This text is divided by blocks of length 5! -hxido ftted elogs iiyke tsdbs nitvb clh +hsboe iontv letid shidy ftekt siblx dcg thistextisdividedbyblocksoflength ------------------------------------------------------------ +================================================================================ I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! -L ohcc taa-inptaseh tvabaeeese. Lerrs tio : ^,&@$~(*;?&#. Naht'h rt! +L lhse nbc-steaaeai acrrtopatt. Nteai vhr : ^,&@$~(*;?&#. Hhoe't es! I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! ------------------------------------------------------------ +================================================================================ text あい だやぎへぐゆぢ text だぐ あぎぢやゆいへ text あい だやぎへぐゆぢ ------------------------------------------------------------ +================================================================================ +ENGLISH_SQUARE_IJ doesn't change Ii to Jj because it's a transposition cipher! +NSUIECG_TBUTRP_TC elsrd'n aijcea Ns op Ei qeotnij ai't s inhghajsheoes saoiir! +ENGLISH_SQUARE_IJ doesn't change Ii to Jj because it's a transposition cipher! ''' diff --git a/secretpy/ciphers/columnar_transposition.py b/secretpy/ciphers/columnar_transposition.py index 4edcd21..0b525a6 100755 --- a/secretpy/ciphers/columnar_transposition.py +++ b/secretpy/ciphers/columnar_transposition.py @@ -9,8 +9,9 @@ class ColumnarTransposition: """ def __keyorder(self, alphabet, key): - chars = map(alphabet.index, key) - return [i for i, _ in sorted(enumerate(chars), key=lambda x: x[1])] + indexes = {c: i for i, letters in enumerate(alphabet) for c in letters} + new_key = map(lambda x: indexes[x], key) + return [i for i, _ in sorted(enumerate(new_key), key=lambda x: x[1])] def encrypt(self, text, key, alphabet=al.ENGLISH): """ From 7945bf9b2fc86a9f276d8c528e8ad1ec1e806db4 Mon Sep 17 00:00:00 2001 From: tigertv Date: Tue, 27 Jul 2021 14:47:40 +0200 Subject: [PATCH 32/33] Add Spiral cipher --- README.rst | 30 ++++---- examples/spiral.py | 89 +++++++++++++++++++++++ secretpy/__init__.py | 4 +- secretpy/ciphers/__init__.py | 3 +- secretpy/ciphers/spiral.py | 133 +++++++++++++++++++++++++++++++++++ tests/test_spiral.py | 64 +++++++++++++++++ 6 files changed, 304 insertions(+), 19 deletions(-) create mode 100755 examples/spiral.py create mode 100755 secretpy/ciphers/spiral.py create mode 100755 tests/test_spiral.py diff --git a/README.rst b/README.rst index 9c8e469..240848a 100644 --- a/README.rst +++ b/README.rst @@ -21,22 +21,20 @@ Description SecretPy is a cryptographic Python package. It uses the following classical cipher algorithms: -- Affine -- Atbash -- Bazeries -- Beaufort -- Caesar, Caesar Progressive -- Chaocipher -- Keyword -- Playfair, Two Square(Double Playfair), Three Square, Four Square -- Polybius, ADFGX, ADFGVX, Bifid, Trifid, Nihilist -- Rot13, Rot5, Rot18, Rot47 -- Scytale -- Simple Substitution -- Transposition - - Columnar, Myszkowski, Zigzag(Railfence) -- Vic -- Vigenere, Autokey, Gronsfeld, Porta +* Affine +* Atbash +* Bazeries +* Beaufort +* Caesar, Caesar Progressive +* Chaocipher +* Keyword +* Playfair, Two Square(Double Playfair), Three Square, Four Square +* Polybius, ADFGX, ADFGVX, Bifid, Trifid, Nihilist +* Rot13, Rot5, Rot18, Rot47 +* Simple Substitution +* Transposition: Columnar, Scytale, Spiral, Myszkowski, Zigzag(Railfence) +* Vic +* Vigenere, Autokey, Gronsfeld, Porta Installation ============ diff --git a/examples/spiral.py b/examples/spiral.py new file mode 100755 index 0000000..0928b7a --- /dev/null +++ b/examples/spiral.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +# -*- encoding: utf-8 -*- + +from secretpy import Spiral, CryptMachine, alphabets as al +from secretpy.cmdecorators import SaveAll, Block, UpperCase + + +cipher = Spiral() +key = 5 +alphabet = al.GERMAN +plaintext = u"schweißgequältvomödentextzürnttypografjakob" + +print(plaintext) +enc = cipher.encrypt(plaintext, key, alphabet) +print(enc) +dec = cipher.decrypt(enc, key, alphabet) +print(dec) + + +def encdec(machine, plaintext): + print("=" * 80) + print(plaintext) + enc = machine.encrypt(plaintext) + print(enc) + print(machine.decrypt(enc)) + + +cm0 = CryptMachine(cipher, key) + +cm = cm0 +cm = UpperCase(Block(cm0)) +key = 5 +cm.set_key(key) +cm.set_alphabet(al.ENGLISH) +plaintext = "WE ARE DISCOVERED FLEE AT ONCE" +encdec(cm, plaintext) + +cm = cm0 +cm.set_alphabet(al.ENGLISH) +plaintext = "I don't love non-alphabet characters and uppercase. I will remove all of them: ^,&@$~(*;?&#." +encdec(cm, plaintext) + +cm = Block(cm, length=5, sep=" ") +plaintext = "This text is divided by blocks of length 5!" +encdec(cm, plaintext) + +cm = SaveAll(cm0) +plaintext = "I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it!" +encdec(cm, plaintext) + +cm.set_alphabet(al.ENGLISH_SQUARE_IJ) +plaintext = "ENGLISH_SQUARE_IJ doesn't change Ii to Jj because it's a transposition cipher!" +encdec(cm, plaintext) + +cm.set_alphabet(al.JAPANESE_HIRAGANA) +cm.set_key(4) +plaintext = u"text あい だやぎへぐゆぢ" +encdec(cm, plaintext) + + +''' +schweißgequältvomödentextzürnttypografjakob +kobagttevqewhcsiuonztrafjonxdtegßämtüypreöl +schweißgequältvomödentextzürnttypografjakob +================================================================================ +WE ARE DISCOVERED FLEE AT ONCE +TONCE ADOER AEWDV FLEEE CSIER +WEAREDISCOVEREDFLEEATONCE +================================================================================ +I don't love non-alphabet characters and uppercase. I will remove all of them: ^,&@$~(*;?&#. +emhlmiapsatpntnodilohccapsloloftaewcurrelevonahtneelverirdeaba +idontlovenonalphabetcharactersanduppercaseiwillremoveallofthem +================================================================================ +This text is divided by blocks of length 5! +gthns bdsts ihted elofl ekyii txido cbv +thistextisdividedbyblocksoflength +================================================================================ +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +T itsr rel-evolinpt asehatseee. Abano hcc : ^,&@$~(*;?&#. Tarh't ha! +I love non-alphabet characters. These are : ^,&@$~(*;?&#. That's it! +================================================================================ +ENGLISH_SQUARE_IJ doesn't change Ii to Jj because it's a transposition cipher! +HERPIPT_EETNNJ_UI lgnes'a dtgoci Ro on Ci tsasbia si'q s hrocejatasins ujihee! +ENGLISH_SQUARE_IJ doesn't change Ii to Jj because it's a transposition cipher! +================================================================================ +text あい だやぎへぐゆぢ +text ぢゆ やだいあぎへぐ +text あい だやぎへぐゆぢ +''' diff --git a/secretpy/__init__.py b/secretpy/__init__.py index be221b5..199772e 100755 --- a/secretpy/__init__.py +++ b/secretpy/__init__.py @@ -9,7 +9,7 @@ ColumnarTransposition, FourSquare, Gronsfeld, Keyword, MyszkowskiTransposition, Nihilist, SimpleSubstitution, Playfair, Porta, Polybius, Rot13, Rot18, Rot47, Rot5, - Scytale, ThreeSquare, Trifid, TwoSquare, Vigenere, Vic, + Scytale, Spiral, ThreeSquare, Trifid, TwoSquare, Vigenere, Vic, Zigzag) __all__ = [ @@ -20,6 +20,6 @@ "Chao", "ColumnarTransposition", "FourSquare", "Gronsfeld", "Keyword", "MyszkowskiTransposition", "Nihilist", "SimpleSubstitution", "Playfair", "Porta", "Polybius", - "Rot13", "Rot18", "Rot47", "Rot5", "Scytale", "ThreeSquare", + "Rot13", "Rot18", "Rot47", "Rot5", "Scytale", "Spiral", "ThreeSquare", "Trifid", "TwoSquare", "Vigenere", "Vic", "Zigzag", ] diff --git a/secretpy/ciphers/__init__.py b/secretpy/ciphers/__init__.py index fc7f794..c9bd6c4 100755 --- a/secretpy/ciphers/__init__.py +++ b/secretpy/ciphers/__init__.py @@ -26,6 +26,7 @@ from .rot47 import Rot47 from .rot5 import Rot5 from .scytale import Scytale +from .spiral import Spiral from .three_square import ThreeSquare from .trifid import Trifid from .two_square import TwoSquare @@ -39,6 +40,6 @@ "Chao", "ColumnarTransposition", "FourSquare", "Gronsfeld", "Keyword", "MyszkowskiTransposition", "Nihilist", "SimpleSubstitution", "Playfair", "Porta", "Polybius", - "Rot13", "Rot18", "Rot47", "Rot5", "Scytale", "ThreeSquare", + "Rot13", "Rot18", "Rot47", "Rot5", "Scytale", "Spiral", "ThreeSquare", "Trifid", "TwoSquare", "Vigenere", "Vic", "Zigzag", ] diff --git a/secretpy/ciphers/spiral.py b/secretpy/ciphers/spiral.py new file mode 100755 index 0000000..97bf4cd --- /dev/null +++ b/secretpy/ciphers/spiral.py @@ -0,0 +1,133 @@ +#!/usr/bin/python +# -*- encoding: utf-8 -*- +from itertools import cycle + + +class Spiral: + """ + The Spiral Transposition Cipher + + It's a variant of the Route Cipher + Spiral inwards, clockwise, starting at the top right. + + https://en.wikipedia.org/wiki/Transposition_cipher#Route_cipher + """ + def __crypt(self, text, key, is_encrypt): + columns, rmd = divmod(len(text), key) + + # init + top = 0 + left = key - 1 + bottom = key * (columns + (rmd > 0)) - 1 + + if rmd: + right = len(text) - rmd + else: + right = len(text) - key + i = right + right -= key + + if is_encrypt: + res = [] + else: + ti = 0 + res = [None] * len(text) + + # i = from, j = to + + # top right to bottom right + j = bottom + if i == j: + if is_encrypt: + res.append(text[i]) + else: + res[i] = text[ti] + return u"".join(res) + temp = j + if temp > len(text): + temp = len(text) + for p in range(i, temp): + if is_encrypt: + res.append(text[p]) + else: + res[p] = text[ti] + ti += 1 + # change limit + bottom -= 1 + key + + # bottom right to bottom left + i = j + if rmd: # additional condition + i -= key + if i < 0: # additional condition + return u"".join(res) + j = left + if i == j and rmd == 0: + if is_encrypt: + res.append(text[i]) + else: + res[i] = text[ti] + return u"".join(res) + for p in range(i, j, -key): + if is_encrypt: + res.append(text[p]) + else: + res[p] = text[ti] + ti += 1 + # change limit + left += key - 1 + + # ([limit, change_limit, delta], ...) + steps = ([top, key + 1, -1], [right, 1 - key, key], [bottom, -key - 1, 1], [left, key - 1, -key]) + + # bottom left to top left + # top left to top right + # top right to bottom right + # bottom right to bottom left + for step in cycle(steps): + i = j + j = step[0] + step[0] += step[1] + if i == j: + if is_encrypt: + res.append(text[i]) + else: + res[i] = text[ti] + break + for p in range(i, j, step[2]): + if is_encrypt: + res.append(text[p]) + else: + res[p] = text[ti] + ti += 1 + return u"".join(res) + + def encrypt(self, text, key, alphabet=None): + """ + Encryption method + + :param text: Text to encrypt + :param key: Number of rows + :param alphabet: Alphabet is not used + :type text: string + :type key: integer + :type alphabet: string + :return: text + :rtype: string + """ + return self.__crypt(text, key, True) + + def decrypt(self, text, key, alphabet=None): + """ + Decryption method + + :param text: Text to decrypt + :param key: Number of rows + :param alphabet: Alphabet is not used + :type text: string + :type key: integer + :type alphabet: string + :return: text + :rtype: string + """ + return self.__crypt(text, key, False) diff --git a/tests/test_spiral.py b/tests/test_spiral.py new file mode 100755 index 0000000..7d13737 --- /dev/null +++ b/tests/test_spiral.py @@ -0,0 +1,64 @@ +#!/usr/bin/python +# -*- encoding: utf-8 -*- + +from secretpy import Spiral, alphabets as al +import unittest + + +class TestSpiral(unittest.TestCase): + alphabet = ( + al.ENGLISH, + al.ENGLISH, + al.ENGLISH, + al.ENGLISH, + al.ENGLISH, + # al.GERMAN, + # al.SPANISH, + ) + + key = ( + 3, + 5, + 5, + 5, + 5, + ) + + plaintext = ( + u"wearediscoveredfleeatoncejx", # no remainder + u"wearediscoveredfleeatoncejck", # with remainder + u"wearediscoveredfleeatoncejckxx", # no remainder + u"manifolds", # with remainder key - 1 + u"manif", # one line, no remainder + u"mani", # one line, with remainder + u"m", # one char, with remainder + u"", # empty + ) + + ciphertext = ( + u"ejxctedecdaewriorfeonalevse", + u"jckeadoeraewdvftonceecsieler", + u"jckxxeadoeraewdvftonceecsieler", + u"oldsfinam", + u"manif", + u"mani", + u"", + ) + + cipher = Spiral() + + def test_encrypt(self): + for i, alphabet in enumerate(self.alphabet): + enc = self.cipher.encrypt( + self.plaintext[i], self.key[i], alphabet) + self.assertEqual(enc, self.ciphertext[i]) + + def test_decrypt(self): + for i, alphabet in enumerate(self.alphabet): + dec = self.cipher.decrypt( + self.ciphertext[i], self.key[i], alphabet) + self.assertEqual(dec, self.plaintext[i]) + + +if __name__ == '__main__': + unittest.main() From 7762dd4145602960cda07ea305bdde4e463705a9 Mon Sep 17 00:00:00 2001 From: tigertv Date: Tue, 27 Jul 2021 19:48:09 +0200 Subject: [PATCH 33/33] Release a new version - Support non-string alphabets - Removed redundant decorators: NoSpaces, SaveSpaces, LowerCase, RemoveNonAlphabet - Fixes and refactoring --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b550a94..9da6139 100755 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name="secretpy", - version="0.11.0", + version="0.12.0", author="Max Vetrov", author_email="maxvetrov555@yandex.ru", description="Classical ciphers",