コード例 #1
0
 def _block_output(self, working_list):
     """Internal method that overrides the base class method.
     Formats the ciphertext in groups of 25 two-digit numbers
     on each line, if the user chooses.  (May also call the base
     class method.)
     
     Called by the encrypt method.
     
     Named arguments:
     - working_list -- the list of numbers constituting the
         ciphertext.
     
     Returns:  nothing.
     """
     # Clear the screen.
     i_o.clear_screen()
     working_string = ""
     if i_o.yes_no("Would you like the output separated" +
                   " into two-digit numbers?"):
         # If yes, check to see if the user wants line breaks.
         line_break = i_o.yes_no(
             "Would you like the encrypted text to be printed" +
             "in\n25-number lines for immproved readability?")
         # Build an output string of two-digit numbers.
         # If yes, insert a new line every 25 numbers.
         working_string = "\n"
         num = 1
         while len(working_list) > 0:
             # Pop numbers off the list one at a time until empty.
             working_string += str(working_list.pop(0)) + " "
             if line_break:
                 # Only use if the user wants line breaks.
                 if num < 25:
                     num += 1
                 else:
                     working_string += "\n"
                     num = 1
                 # end if
             # end if
         # end while
         self.ciphertext = working_string
     else:
         # If no, dump the entire list into ciphertext as one
         #  string.
         self.ciphertext = "".join(str(n) for n in working_list)
         # Then call the original method.
         super()._block_output()
     return
コード例 #2
0
 def _get_keynumber(self, prompt, keylist=None, lbound=None, ubound=None):
     """Gets a keynumber for a cipher from the unser allows the user
     to abort.
     
     Arguments:
     - prompt -- prompt for the user.
     
     Named arguments:
     - keylist -- a list of valid entries (default None).
     - lbound -- lower bound for number, inclusive (default None).
     - ubound -- upper bound for number, inlcusive (default None).
     
     Returns:  the keynumber, or None if the user aborts.
     """
     keynumber = None
     got_keynumber = False
     # Loop until a valid key is obtained, or user aborts.
     while not got_keynumber:
         # Get a string response.
         string = i_o.get_string(prompt)
         # If the user didn't enter anything...
         if len(string) == 0:
             # Ask whether to abort.
             abort = i_o.yes_no(
                 "You did not enter anything.  Do you want to abort?")
             if abort:
                 # If yes, drop out of the while loop with key =
                 #  None.
                 break
         else:
             # Test the response for validity.
             got_keynumber = True
             # First, see if it's a number.
             try:
                 keynumber = int(string)
             except ValueError:
                 # Loop back if it's not.
                 print("Sorry, that was not a number.")
                 got_keynumber = False
                 continue
             # end try
             # Check the number against the keylist (but only if
             #  keylist exists).
             if keylist and (keynumber not in keylist):
                 # Loop if there's a keylist and the number isn't in
                 #  it.
                 print("Sorry, that is not a valid keynumber for this",
                       "cipher.")
                 got_keynumber = False
             # Check against upper and lower bounds, if they exist.
             elif lbound and (keynumber < lbound):
                 print("Sorry, that number is too small.")
                 got_keynumber = False
             elif ubound and (keynumber > ubound):
                 print("Sorry, that number is too large.")
                 got_keynumber = False
             # end if
         # end if
     # end while
     return keynumber
コード例 #3
0
 def _one_time_pad(self):
     """Internal method that implements a one-time pad at the
     user's option.
     
     Called by both encrypt and decrypt methods.
     
     Arguments:  none.
     
     Returns:  nothing.
     """
     # Clear the screen.
     i_o.clear_screen()
     # Print summary info.
     print("Cipher: ", self.__str__())
     print("Action: ", self.mode, "\n")
     # Print explanation of the one-time pad.
     if self.mode == "Encrypt":
         print(
             "One-Time Pad:  In addition to encrypting your message\n",
             "using the " + self.__str__() + ", Secret Messages! can\n",
             "first encode your message using a one-time pad.  This\n",
             "scrambles your message before it is encrypted.  WARNING--\n",
             "if you use a one-time pad code, your message will be\n",
             "unrecoverable without entering the same code while\n",
             "decrypting.  To be theoretically unbreakable, the one-time\n",
             "pad code must equal or exceed the length of your message,\n",
             "but a code of any length may be used.")
     else:
         print(
             "One-Time Pad:  If this message was encrypted using a\n",
             "one-time pad code, you MUST enter the same code now in\n",
             "order to decrypt the message.")
     # If user chooses to use a one-time pad...
     if i_o.yes_no("Do you want to use a one-time pad on this cipher?"):
         done = False
         # Loop until a code is obtained, or user aborts.
         while done is False:
             # Get the one-time pad code from the user.
             pad_code = self._get_keyword("Enter a one-time code now:  ")
             if pad_code == "":
                 if i_o.yes_no(
                         "Do you want to " + self.mode.lower() + "this " +
                         "message without a one-time pad code?"):
                     # If no one-time pad code, do nothing.
                     return
                 # end if (method exits)
             else:
                 done = True
             # end if
         # end while
         # Work pad magic here.  Simple modular addition/subtraction
         #  is used.
         alphanum = ALPHABET + NUMBERS
         # Convert the pad code to a list of numbers.
         pad_code_list = []
         for letter in pad_code:
             pad_code_list.append(alphanum.index(letter.upper()))
         # end for
         new_string = ""
         if self.mode == "Encrypt":
             mod = 1
         else:
             mod = -1
         # end if
         # This method operates on both letters and numbers.
         # Loop through the text, performing addition or subtraction
         #  on each letter, using each number in the pad code in
         #  succession.  Note that if the one-time pad code is
         #  shorter than the message, the code repeats.
         index = 0
         for letter in self.plaintext:
             # Substitute recoded letter for original letter.
             new_string += (
                 alphanum[(alphanum.index(letter) +
                           (pad_code_list[index] * mod)) % 36])
             # Next number in code sequence; reset if at end.
             index = (index + 1) % len(pad_code_list)
         # end for
         # Put the results back into the plaintext attribute.
         self.plaintext = new_string
     # end if
     return
コード例 #4
0
 def _intelligent_encrypt(self):
     """Internal method that inserts flags for decryption.
     
     If the user opts for intelligent encryption, this method will
     insert special sequences for spaces, capital letters, basic
     punctuation (and itself), using bigrams (2-letter combinations)
     that rarely occur in English.
     
     Arguments:  none.
     
     Returns:  nothing.
     """
     # Clear the screen first.
     i_o.clear_screen()
     # Print summary info.
     print("Cipher: ", self.__str__())
     print("Action: ", self.mode, "\n")
     # Print explanation of intelligent encryption.
     print(
         "Intelligent Encryption/Decryption:  Under ordinary\n",
         "circumstances, when a message is encrypted it is turned into\n",
         "a single string of upper-case text, with all spacing,\n",
         "punctuation and capitalization removed.  Secret Messages!\n",
         "can encrypt your message so that flags are inserted to\n",
         "indicate spacing, punctuation and capitalization, which can\n",
         "then be restored upon decryption.\n")
     print(
         "Note that Intelligent Encryption/Decryption uses the\n",
         "following letter combinations, which do not occur in\n",
         "most Roman-alphabet-based languages:  [FQ], [GX], [HX],\n",
         "[JQ], [JX], [PZ], [QG], [QK], [QY], [QZ], [WQ], [WZ], [XJ],\n",
         "[ZJ], [ZQ], [ZX].  If your messages contains abbreviations,\n",
         "code words, model numbers, map coordinates, etc., which may\n",
         "contain these letter combinations, you should NOT select\n",
         "Intelligent Encryption/Decryption.\n")
     # Get the user's choice.
     use_intel = i_o.yes_no("Use Intelligent Encryption?")
     if not use_intel:
         # If no, just exit.
         return
     else:
         # If yes, The first two characters of the decrypted text
         # will be "ZX", which will trigger _intelligent_decrypt when
         # it is called.
         space_sequences = ["FQ", "JX", "QK", "WZ", "ZJ"]
         new_text = "ZX"
         # Go through the message one character at a time.
         for char in self.plaintext:
             # Check for space.
             if char == " ":
                 # Because spaces are so common, encoding them with a
                 #  single escape sequence could expose the sequence
                 #  to detection, thereby exposing the lengths of
                 #  individiual words.  To counter this, the method
                 #  randomly selects one of five special sequences,
                 #  any of which can mark a space.
                 new_text += space_sequences[random.randint(0, 4)]
             # First a series of tests for punctuation marks.  Each
             #  of these inserts a two-character sequence in place of
             #  the character.
             elif char == ".":
                 new_text += "HX"
             elif char == ",":
                 new_text += "JQ"
             elif char == "?":
                 new_text += "PZ"
             elif char == "!":
                 new_text += "QG"
             elif char == "'":
                 new_text += "QY"
             elif char == '"':
                 new_text += "QZ"
             elif char == ":":
                 new_text += "WQ"
             elif char == ";":
                 new_text += "XJ"
             elif char == "-":
                 new_text += "ZQ"
             # If it's not punctuation, check for a capital letter.
             elif char in ALPHABET:
                 new_text += "GX" + char
             else:
                 # If all else fails, it's just an ordinary letter/
                 #  number.
                 new_text += char.upper()
             # end if
         # end for
         # The message also ends with "ZX".  Any characters added
         #  by the encryption method are nulls and should be
         #  discarded by _intelligent_decrpyt.
         new_text += "ZX"
         self.plaintext = new_text
     # end if
     return
コード例 #5
0
 def _get_keyword(
     self, prompt, keylist=ALPHABET, max_length=None, min_length=None):
     """Gets a keyword for a cipher from the user, allows the user to
     abort.
     
     The primary difference between _get_keyword and an ordinary 
     input method like get_string is that _get_keyword ensures 
     that no non-alphabetic characters are in the keyword (spaces
     are stripped) and that the keyword is returned in upper-case.        
     
     Arguments:
     - prompt -- prompt for the user (allows keywords to be named).
     
     Named Arguments:
     - keylist -- allows the caller to pass a non-standard alphabet
         against which to check the user's input (default ALPHABET).
     - max_length -- allows the caller to control the maximum length
         of the keyword (default None).
     - min_length -- allows the caller to control the minimum length
         of the keyword (default None).
     
     Returns:  the keyword, or an empty string if the user aborts.
     """
     keyword = ""
     got_keyword = False
     # Loop until a valid keyword is obtained, or user aborts.
     while not got_keyword:
         # Get string response.
         keyword = i_o.get_string(prompt)
         # If the user didn't enter a keyword...
         if len(keyword) == 0:
             # Ask whether to abort.
             abort = i_o.yes_no(
                 "You did not enter anything.  Do you want to abort?")
             if abort:
                 # If user aborts, drop out of the while loop with
                 #  keyword = "", which will be returned.
                 break
             # end if
         # end if
         if min_length and (len(keyword) < min_length):
             # If too short, say so and loop back to beginning.
             print(
                 "Sorry, your entry is too short.")
             continue
         # end if
         if max_length and (len(keyword) > max_length):
             # If too long, say so and loop back to beginning.
             print("Sorry, your entry is too long.")
             continue
         # end if
         # If it's the right length, check for invalid characters.
         got_keyword = True
         for letter in keyword:
             # Check each character to make sure it's a letter.
             if not (letter.upper() in keylist):
                 print(
                     "Sorry, your entry includes spaces or" +
                     "other forbidden characters.")
                 got_keyword = False
                 # Break the for loop (not the while loop).
                 break
             # end if
         # end for
     # end while
     return keyword.upper()
コード例 #6
0
 def _block_output(self):
     """Internal method that outputs encrypted text in five-
     character blocks, and can also insert newlines to keep long
     strings of blocks from running off the screen. if the user
     wishes.
     
     Called by the encrypt method.
     
     Arguments:  none.
     
     Returns:  nothing.
     """
     # Clear the screen.
     i_o.clear_screen()
     # Ask whether to break the output into 5-character blocks.
     separate = i_o.yes_no(
             "Would you like the encrypted text to be printed in" +
             "five\n-character blocks for immproved readability?")
     line_break = i_o.yes_no(
             "Would you like the output to be broken into separate" +
             'lines?\n(Warning:  This will insert line breaks or") +
             '"hard returns"\ninto the output.)')
     new_text = ""
     if separate:
         index = 0
         # Iterate over the ciphertext, five characters at a time.
         for pos in range(0, len(self.ciphertext), 5):
             # Add a five-character block, plus a space.
             new_text += self.ciphertext[pos:pos+5] + " "
             index += 1
             if index == 10:
                 index = 0
             # end if
         # end for
         # Put result in ciphertext.
         self.ciphertext = new_text
     # end if
     # Ignore if the ciphertext is too short to break into multiple
     #  lines.
     # Set line length.
     pos = 60
     if line_break and (len(self.ciphertext) > pos):
         # Start with a new line.
         new_text = "\n"
         while pos < len(self.ciphertext):
             # Work backwards from the first character after the line
             #  length, looking for a space.
             offset = 0
             while (
                     (self.ciphertext[pos + offset] != " ") and
                     (pos + offset != 0)):
                 offset -= 1
             # end while
             if offset == 0:
                 # If offset landed on 0, the first character after
                 #  the line length is a space.  In that case, take
                 #  the line, insert a newline character, and discard
                 #  the space.
                 new_text += self.ciphertext[:pos] + "\n"
                 self.ciphertext = self.ciphertext[pos+1:]
             elif pos + offset == 0:
                 # If offset landed on the negative of pos, there
                 #  were no spaces within the line.  Just take the
                 #  entire line.
                 new_text += self.ciphertext[:pos] + "\n"
                 self.ciphertext = self.ciphertext[pos:]
             else:
                 # Otherwise, take the line up to and including the
                 #  space.
                 new_text += self.ciphertext[:pos + offset + 1] + "\n"
                 self.ciphertext = self.ciphertext[pos + offset + 1:]
             # end if
         # end while
         # When there is less than a full line left, take the entire
         #  line.
         new_text += self.ciphertext
         # Put result back in self.ciphertext.
         self.ciphertext = new_text
     # end if
     return
コード例 #7
0
def main():
    """The main script function.
    
    Arguments:  none.
    
    Returns:  nothing.
    """
    # Opening screen.
    i_o.welcome_screen()
    running = True
    # Runs until user quits.
    while running:
        # User chooses to encrypt or decrypt here.
        a_choice, action = i_o.input_from_menu(
            ["Encrypt", "Decrypt"], option_type="actions",
            allow_keystroke=True, keystroke_list=["E", "D"], confirm=True)
        # Runs only if user doesn't quit.
        if a_choice:
            action = action[0]
            print("You have chosen to " + action + ".\n")
            # User chooses a cipher here.
            c_choice, chosen_cipher = i_o.input_from_menu(
                IMPLEMENTED_CIPHERS, option_type="ciphers",
                allow_keystroke=True, keystroke_list=CIPHER_KEYSTROKES,
                confirm=True)
            # Runs only if user doesn't quit.
            if c_choice:
                chosen_cipher = chosen_cipher[0]
                print("You have selected " + chosen_cipher + ".\n")
                # User enters text here.
                text = i_o.get_string(
                    "Please enter your text, or [ENTER] to go back:\n>>  ")
                # Runs only if user enters something
                if len(text) > 0:
                    # Create an object of the appropriate cipher class.
                    #  Then call the object's encrypt or decrypt method
                    #  with the user's text.
                    cipher = CIPHER_CLASS[chosen_cipher](action, text)
                    if action == "Encrypt":
                        cipher.encrypt()
                        output = cipher.ciphertext
                    else:
                        cipher.decrypt()
                        output = cipher.plaintext
                    # end if
                    # If the method set nothing, the user aborted.
                    if len(output) == 0:
                        print("Process aborted.")
                    # Else print the result.
                    else:
                        i_o.print_string(output, "Here is your result:  ")
                    # end if
                    # Finished with the instance, so delete it.
                    del cipher
                # end if
            # end if
            repeat = i_o.yes_no("Run again?")
            if not repeat:
                print("Thank you for using Secret Messages!")
                running = False
            # end if
        else:
            print("Thank you for using Secret Messages!")
            running = False