Python Forum
A deciphering problem
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
A deciphering problem
#1
Break the following ciphertext, decrypting one line at a time because each
line has a different key. Remember to escape any quote characters:
qeFIP?eGSeECNNS,
5coOMXXcoPSZIWoQI,
avnl1olyD4l'ylDohww6DhzDjhuDil,
z.GM?.cEQc. 70c.7KcKMKHA9AGFK,
?MFYp2pPJJUpZSIJWpRdpMFY,
ZqH8sl5HtqHTH4s3lyvH5zH5spH4t pHzqHlH3l5K
Zfbi,!tif!xpvme!qspcbcmz!fbu!nfA



my solution:

thelist = ["qeFIP?eGSeECNNS,", "5coOMXXcoPSZIWoQI,", "avnl1olyD4l'ylDohww6DhzDjhuDil,",  "z.GM?.cEQc. 70c.7KcKMKHA9AGFK,", "?MFYp2pPJJUpZSIJWpRdpMFY,", "ZqH8sl5HtqHTH4s3lyvH5zH5spH4t pHzqHlH3l5K", "Zfbi,!tif!xpvme!qspcbcmz!fbu!nfA"]

SYMBOLS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?.'

for i in thelist:
    for key in range(len(SYMBOLS)):
        translated = ''
        for symbol in i:
            if symbol in SYMBOLS:
                symbolIndex = SYMBOLS.find(symbol)
                translatedIndex = symbolIndex - key

                if translatedIndex < 0:
                    translatedIndex = translatedIndex + len(SYMBOLS)
                translated = translated + SYMBOLS[translatedIndex]
            else:
                translated = translated + symbol

        print(f'Key #{key} {translated}')
The output is very long so I won't past it but in short, it takes every element in the list, runs all the keys (in the length of SYMBOLS string), prints all, and one of them is the correct key.
Is there any way to improve this code so that I can see only deciphered lines? The catch is that each line from the task setting has a different key.
Not sure if my choice of the list is the right way to go...
This is how the solution should look like:

I love my kitty,
My kitty loves me,
Together we're happy as can be,
Though my head has suspicions,
That I keep under my hat,
Of what if I shrank to the size of a rat.
Yeah, she would probably eat me.
Reply
#2
That is an interesting problem.
Perhaps you could split the translated line and then run pyspellchecker against each word in the line. The line with the least errors would probably be the right solution.
Truman likes this post
Reply
#3
This is a Cesar cypher.
The question is, did you get the solution beforehand,
as part of the exercise?
Because then you can calculate the offset(s),
without having to revert to trial and error,
I see no obvious logic in the 7 keys as a sequence or so.
The first line key = 32.
Paul
Output:
I love my kitty ********** My kitty loves me ********** Together were happy as can be ********** Though my head has suspicions ********** That I keep under my hat ********** Of what if I shrank to the size of a rat. ********** Yeah she would probably eat me.
It is more important to do the right thing, than to do the thing right.(P.Drucker)
Better is the enemy of good. (Montesquieu) = French version for 'kiss'.
Reply
#4
(Aug-16-2021, 07:19 AM)DPaul Wrote: I see no obvious logic in the 7 keys as a sequence or so.
Of course there is a logic: it is to stimulate you to decode it with a program, not by hand! Smile
(Aug-16-2021, 07:19 AM)DPaul Wrote: The first line key = 32
Note that Truman subtracts so his result is len(SYMBOLS) - 32 = 34. With that method one would get:
Output:
KEY TEXT 34 I love my kitty, 44 My kitty loves me, 7 Together we're happy as can be, 32 Though my head has suspicions, 45 That I keep under my hat, 11 Of what if I shrank to the size of a rat. 1 Yeah, she would probably eat me.
(Aug-16-2021, 07:19 AM)DPaul Wrote: The question is, did you get the solution beforehand,
as part of the exercise?
Because then you can calculate the offset(s),
without having to revert to trial and error,
That would not be "good sport", would it?

@Truman, I wrote another poem for you. Do you like it?
['iex?LMC9HeHI0F?G9H:',
 '!LMWoQSVRMRK,oQcoKEVHIRIVoTEPIoJVSQoJVMKLX,',
 '‘Thz1ly,DvulDtvtlu1,Dwslhzl’,DjhtlDy2uupunDpuzpklG',
 '‘oFcQGF0 JcJGK -8MK.cocO7Kc9MLLAF?cK.GGLc7!L JcK.GGL',
 'tSIpbMJSp2pYZWSJIpFSIpQTTPJI,pLWNRpwJFYMpYMJWJpXYTTIs',
 'TH8l4Hl11lwwpoHlyoHm0H5spHz5sp3H8l0HTHqwpo,',
 'Cvu!tujmm!eftdsjfe!ijt!iboe!dbtujoh!b!uisfbuA',
 'u9MN?L,eSIOLeBILM?,e9H!eQCNBeAI!MJ??!eF?NeG?eLC!?',
 '!So1WTELER,oaLMGLo1oQEcoVIEGLoIVIoJEPPoSJoRMKLXr’',
 'aopzDhm1lyuvvuD–DsvunDhm1lyDolDohkDzwlkD–',
 'oFcL. cH7JCcG!c9 07JK,cj 7L.cALcO7KcocE Lf',
 '‘BMd,’pYMZXp2pFXPJI,pbMNQJpMJpXYTTIpbFNYNSLpYMJWJ,',
 '‘OtoH0z6,H5st4Hxz3y,Hrt7pHx0H4p37ly5H46nsHlH4nl3pJ’',
 'Tnjmjohmz!dbnf!ijt!sfqmz:!‘Op!uisfbu,!gps!tvsf,!ju!xbt',
 '2B9NeM?HNeSIOLeA9L!?H?Le.F??CHAhe1OLJLCM?!eqeQ9M',
 '!SoJMRH,oMRoIEVPcoQSVR,oLIVIoWXMPPoEXoaSVOoEoQER',
 'dov,D1opzDzhtlDl3lupun,DPDhtD1vD1hrlDpuDPzwhohuG’']
Reply
#5
I made my own version of a cipher/decipher and solved ibreeden's
from dataclasses import dataclass
import random
from typing import List

ibreeden_list = [
    "iex?LMC9HeHI0F?G9H:",
    "!LMWoQSVRMRK,oQcoKEVHIRIVoTEPIoJVSQoJVMKLX,",
    "‘Thz1ly,DvulDtvtlu1,Dwslhzl’,DjhtlDy2uupunDpuzpklG",
    "‘oFcQGF0 JcJGK -8MK.cocO7Kc9MLLAF?cK.GGLc7!L JcK.GGL",
    "tSIpbMJSp2pYZWSJIpFSIpQTTPJI,pLWNRpwJFYMpYMJWJpXYTTIs",
    "TH8l4Hl11lwwpoHlyoHm0H5spHz5sp3H8l0HTHqwpo,",
    "Cvu!tujmm!eftdsjfe!ijt!iboe!dbtujoh!b!uisfbuA",
    "u9MN?L,eSIOLeBILM?,e9H!eQCNBeAI!MJ??!eF?NeG?eLC!?",
    "!So1WTELER,oaLMGLo1oQEcoVIEGLoIVIoJEPPoSJoRMKLXr’",
    "aopzDhm1lyuvvuD–DsvunDhm1lyDolDohkDzwlkD–",
    "oFcL. cH7JCcG!c9 07JK,cj 7L.cALcO7KcocE Lf",
    "‘BMd,’pYMZXp2pFXPJI,pbMNQJpMJpXYTTIpbFNYNSLpYMJWJ,",
    "‘OtoH0z6,H5st4Hxz3y,Hrt7pHx0H4p37ly5H46nsHlH4nl3pJ’",
    "Tnjmjohmz!dbnf!ijt!sfqmz:!‘Op!uisfbu,!gps!tvsf,!ju!xbt",
    "2B9NeM?HNeSIOLeA9L!?H?Le.F??CHAhe1OLJLCM?!eqeQ9M",
    "!SoJMRH,oMRoIEVPcoQSVR,oLIVIoWXMPPoEXoaSVOoEoQER",
    "dov,D1opzDzhtlDl3lupun,DPDhtD1vD1hrlDpuDPzwhohuG’",
]

SYMBOLS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?."


@dataclass
class CipherData:
    shift: str
    result: str


@dataclass
class CipherLine:
    line: str
    cipher_data_possibilites: List[CipherData]


@dataclass
class CeaserCipher:
    symbols: str

    def _shift_symbols_right(self, shift: int) -> str:
        return self.symbols[shift:] + self.symbols[:shift]

    def _shift_symbols_left(self, shift: int) -> str:
        shift = len(self.symbols) - shift
        return self.symbols[shift:] + self.symbols[:shift]

    def cipher(self, line: str, shift: int):
        shifted_sybols = self._shift_symbols_right(shift)
        result = line.translate(line.maketrans(self.symbols, shifted_sybols))
        return CipherData(shift, result)

    def decipher(self, line: str, shift: int) -> str:
        shifted_sybols = self._shift_symbols_left(shift)
        result = line.translate(line.maketrans(self.symbols, shifted_sybols))
        return CipherData(shift, result)

    def decipher_all_possibilties(self, line: str) -> list[str]:
        return [self.decipher(line, index) for index, _ in enumerate(self.symbols)]

    def cipher_random_shift(self, line: str) -> str:
        return self.cipher(line, random.randint(0, len(self.symbols)))


cipherer = CeaserCipher(SYMBOLS)
cipher_lines = [
    CipherLine(line, cipherer.decipher_all_possibilties(line)) for line in ibreeden_list
]

solved_index = (34, 44, 7, 32, 45, 11, 1, 34, 44, 7, 32, 45, 11, 1, 34, 44, 7)


for index, cipher_line in zip(solved_index, cipher_lines):
    print(cipher_line.cipher_data_possibilites[index])
Output:
CipherData(shift=34, result='A Persian nobleman:') CipherData(shift=44, result='This morning, my gardener pale from fright,') CipherData(shift=7, result='‘Master, one moment, please’, came running inside.') CipherData(shift=32, result='‘In yonder rose-bush I was cutting shoot after shoot') CipherData(shift=45, result='And when I turned and looked, grim Death there stood.') CipherData(shift=11, result='I was appalled and by the other way I fled,') CipherData(shift=1, result='But still descried his hand casting a threat.') CipherData(shift=34, result='Master, your horse, and with godspeed let me ride') CipherData(shift=44, result='To Ispahan, which I may reach ere fall of night.’') CipherData(shift=7, result='This afternoon – long after he had sped –') CipherData(shift=32, result='In the park of cedars, Death it was I met.') CipherData(shift=45, result='‘Why,’ thus I asked, while he stood waiting there,') CipherData(shift=11, result='‘Did you, this morn, give my servant such a scare?’') CipherData(shift=1, result='Smilingly came his reply: ‘No threat, for sure, it was') CipherData(shift=34, result='That sent your gardener fleeing. Surprised I was') CipherData(shift=44, result='To find, in early morn, here still at work a man') CipherData(shift=7, result='Who, this same evening, I am to take in Ispahan.’')

I then used
for line in mystery_list:
    print(cipherer.cipher_random_shift(line).result)
to create a new one
yoriz_list = [
    "Svr! zw!3Nz0Nsv  v9N yr5N!x3BQ",
    "XC952v2?P2!Pux??x P?1t7P26952v2?S",
    "HXbeaTzXhzQTiiTgziWPczRdbeaTm3",
    "tRPSOHanLVnEHWWHUnWKDQnFRPSOLFDWHGq",
    "AgVo6dn6WZooZm6ocVi6iZnoZY9",
    "xG6IJ0b.Jb70KK0IbK?6Eb90EJ0e",
    "LYUXUVcfcns5Wiohnm8",
    "uD75 3.Y53G7GY3F7B'HYGD75 3.Y7BCI90YHCY4F73?YH07YFI.7Gb",
    "mJRFMSEFiNP?ARGA?JGRWi.C?RQiNSPGRWl",
    "cBB?BCUC6?E02U!3F3BU.yCCUC703!D0IX",
    "o86y??QyD063w3.6EQ?36y8wyxT",
    "qHeNB?e.9 ?eI.e9G0CAOCNS,eL?.OM?eNB?eN?GJN9NCIHeNIeAO?MMh",
    "DRObOucRYeVNuLOuYXO--uKXNuZbOPObKLViuYXViuYXOu--YLfSYecugKiudYuNYuSdx",
    "3ZhVciUVyhVOhykOmyaOmybchyPSycPjWcigyOhyTWfghyibZSggymci'fSy6ihQV2",
    "i0DR4.RwzAAz?RA3v9R9zCz?U",
    "Z E7.F67V?4G4CV8DV.5E4?V14EE4CVE7z?V*C867E*V?.HY",
    "d1RA3zR48 7z8z9AvA409R4.R3v?yRA0RzE 7v49,R4A'.RvRwvyR4yzvU",
    "7PudROuSWZVOWOXdKdSYXuScuOKciudYuOhZVKSX,uSduWKiuLOuKuQYYNuSNOKx",
    "Zmyq52moq5Im4qI1zqIt1zwuzsIs4qm6IupqmI--Ixq6'5Ip1Iy14qI1rI6t15qJ",
]
Edit: added from typing import List so it works with pre 3.9 python versions
ibreeden likes this post
Reply
#6
Yoriz, I'll need to grasp some more knowledge to be able to catch up with your code.
Thank you.
Reply
#7
It makes use of
https://docs.python.org/3/library/stdtyp....translate Wrote:str.translate(table)
Return a copy of the string in which each character has been mapped through the given translation table. The table must be an object that implements indexing via __getitem__(), typically a mapping or sequence. When indexed by a Unicode ordinal (an integer), the table object can do any of the following: return a Unicode ordinal or a string, to map the character to one or more other characters; return None, to delete the character from the return string; or raise a LookupError exception, to map the character to itself.

You can use str.maketrans() to create a translation map from character-to-character mappings in different formats.

See also the codecs module for a more flexible approach to custom character mappings.
Reply
#8
The keys are indeed (32, 22, ...) or (34, 44,...) depending on adding or subtracting.

The reason I asked if the solution was part of the initial data, is that i see limited use
in decoding with translation or spelling tables etc...

With a nice little poem it's feasible, but what if your message is essentially GPS codes,
longitudes, latitudes, distances,.... You'll end up in the wrong place. Smile

I was looking for a generic solution, i'm very curious what that might be.

In the movie, Enigma was broken because messages always ended with the same 2 words.
Modern codemakers may have learned from that.

Paul
ibreeden likes this post
It is more important to do the right thing, than to do the thing right.(P.Drucker)
Better is the enemy of good. (Montesquieu) = French version for 'kiss'.
Reply
#9
(Aug-17-2021, 06:19 AM)DPaul Wrote: The reason I asked if the solution was part of the initial data, is that i see limited use
in decoding with translation or spelling tables etc...

With a nice little poem it's feasible, but what if your message is essentially GPS codes,
longitudes, latitudes, distances,.... You'll end up in the wrong place.
Indeed Paul, I agree with you completely. Practical use is limited.
But as this is in the "Homework" section, I considered it just as a nice riddle.
(Aug-17-2021, 06:19 AM)DPaul Wrote: I was looking for a generic solution, i'm very curious what that might be.
I challenge you to join the game and find a better solution. Smile
Reply
#10
Fair enough.

You said that including the solution is not "good sport".
The fact of the matter is that TS does have it,
but he/she has not confirmed that is was part of the "problem".

Still we have been able to decuce from that:
1) It is plain text
2) There are no numbers
3) most importantly, it is in English.

Without that information, you could be spelling checking until the cows come home.

Therefore ,I suspect that the statement of the problem is incomplete. If you have
the solution, why not use it to calculate the offsets.

(Even frequency analysis is of little use, because the first sentence (I love my Kitty) ,
has more Y than E. And every sentence has a different key.)

Paul
ibreeden likes this post
It is more important to do the right thing, than to do the thing right.(P.Drucker)
Better is the enemy of good. (Montesquieu) = French version for 'kiss'.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020