This program is meant to act as an example of how to use ME with data that needs to be obfuscated. The functionality provided via the GUI demonstrates both the ability to encrypt and decrypt all text that the UTF-8 encoding can handle. Explanations come later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | """Demonstrate usage of the Markov Encryption module's features.
This program is meant to act as an example of how to use ME with
data that needs to be obfuscated. The functionality provided via
the GUI demonstrates both the ability to encrypt and decrypt all
text that the UTF-8 encoding can handle. Explanations come later."""
__author__ = 'Stephen "Zero" Chappell <Noctis.Skytower@gmail.com>'
__date__ = '13 March 2012'
__version__ = 2, 0, 0
################################################################################
# Import functions, classes, and modules needed to create ME demo.
from tkinter import NoDefaultRoot, Tk, StringVar, BooleanVar
from tkinter.ttk import \
Frame, LabelFrame, Radiobutton, Checkbutton, Label, Entry
from tkinter.constants import W, EW, NSEW, WORD, SEL, END, NORMAL, DISABLED
from tkinter.scrolledtext import ScrolledText
import traceback
import ast
import me
################################################################################
class MarkovDemo(Frame):
"MarkovDemo(master=None, **kw) -> MarkovDemo instance"
TEXT = dict(height=2, width=46, wrap=WORD) # Text Options
GRID = dict(padx=5, pady=5) # Grid Options
# Initialize a MarkovDemo instance with a GUI for interaction.
def __init__(self, master=None, **kw):
"Initialize the MarkovDemo instance's widgets and settings."
super().__init__(master, **kw)
self.build_widgets()
self.place_widgets()
self.setup_widgets()
self.grid_rowconfigure(2, weight=1)
self.grid_rowconfigure(3, weight=1)
self.grid_columnconfigure(0, weight=1)
self.key = self.primer = None
def build_widgets(self):
"Build the various widgets that will be used in the program."
# Create processing frame widgets.
self.processing_frame = LabelFrame(self, text='Processing Mode:')
self.mode_var = StringVar(self, 'encode')
self.decode_button = Radiobutton(self.processing_frame,
text='Decode Cipher-Text',
command=self.handle_radiobuttons,
value='decode',
variable=self.mode_var)
self.encode_button = Radiobutton(self.processing_frame,
text='Encode Plain-Text',
command=self.handle_radiobuttons,
value='encode',
variable=self.mode_var)
self.freeze_var = BooleanVar(self, False)
self.freeze_button = Checkbutton(self.processing_frame,
text='Freeze Key & Primer',
command=self.handle_checkbutton,
offvalue=False,
onvalue=True,
variable=self.freeze_var)
# Create encoding frame widgets.
self.encoding_frame = LabelFrame(self, text='Encoding Options:')
self.chain_size_label = Label(self.encoding_frame, text='Chain Size:')
self.chain_size_entry = Entry(self.encoding_frame)
self.plain_text_label = Label(self.encoding_frame, text='Plain-Text:')
self.plain_text_entry = Entry(self.encoding_frame)
# Create input frame widgets.
self.input_frame = LabelFrame(self, text='Input Area:')
self.input_text = ScrolledText(self.input_frame, **self.TEXT)
# Create output frame widgets.
self.output_frame = LabelFrame(self, text='Output Area:')
self.output_text = ScrolledText(self.output_frame, **self.TEXT)
def place_widgets(self):
"Place the widgets where they belong in the MarkovDemo frame."
# Locate processing frame widgets.
self.processing_frame.grid(sticky=EW, **self.GRID)
self.decode_button.grid(row=0, column=0, **self.GRID)
self.encode_button.grid(row=0, column=1, **self.GRID)
self.freeze_button.grid(row=0, column=2, **self.GRID)
# Locate encoding frame widgets.
self.encoding_frame.grid(sticky=EW, **self.GRID)
self.chain_size_label.grid(row=0, column=0, sticky=W, **self.GRID)
self.chain_size_entry.grid(row=0, column=1, sticky=EW, **self.GRID)
self.plain_text_label.grid(row=1, column=0, sticky=W, **self.GRID)
self.plain_text_entry.grid(row=1, column=1, sticky=EW, **self.GRID)
self.encoding_frame.grid_columnconfigure(1, weight=1)
# Locate input frame widgets.
self.input_frame.grid(sticky=NSEW, **self.GRID)
self.input_text.grid(sticky=NSEW, **self.GRID)
self.input_frame.grid_rowconfigure(0, weight=1)
self.input_frame.grid_columnconfigure(0, weight=1)
# Locate output frame widgets.
self.output_frame.grid(sticky=NSEW, **self.GRID)
self.output_text.grid(sticky=NSEW, **self.GRID)
self.output_frame.grid_rowconfigure(0, weight=1)
self.output_frame.grid_columnconfigure(0, weight=1)
def setup_widgets(self):
"Setup each widget's configuration for the events they handle."
self.input_text.bind('<Key>', self.handle_key_events)
self.input_text.bind('<Control-Key-a>', self.handle_control_a)
self.input_text.bind('<Control-Key-/>', lambda event: 'break')
self.output_text['state'] = DISABLED
self.output_text.bind('<Control-Key-a>', self.handle_control_a)
self.output_text.bind('<Control-Key-/>', lambda event: 'break')
########################################################################
# Take care of any special event needing dedicated processing.
def handle_radiobuttons(self):
"Change the interface based on the encoding / decoding setting."
if self.encrypting:
self.freeze_button.grid()
if not self.freeze_var.get():
self.encoding_frame.grid()
else:
self.freeze_button.grid_remove()
if not self.freeze_var.get():
self.encoding_frame.grid_remove()
self.handle_key_events(None)
def handle_checkbutton(self):
"Change the interface based on the key / primer freeze setting."
if self.freeze_var.get():
self.encoding_frame.grid_remove()
else:
self.encoding_frame.grid()
def handle_key_events(self, event):
"Schedule refreshing the output area after an input area event."
if event is None or event.char and event.state | 0o11 == 0o11:
self.after_idle(self.refresh)
@staticmethod
def handle_control_a(event):
"Select all text in the widget associated with the given event."
event.widget.tag_add(SEL, 1.0, END + '-1c')
return 'break'
########################################################################
# Handle interface's updates when either encoding or decoding.
def refresh(self):
"Refresh the output based on the value of the input."
text = self.input_text.get(1.0, END + '-1c')
if not text:
self.output = text
elif self.encrypting:
self.encode(text)
else:
self.decode(text)
def output(self, value):
"Set the text in the output area to the string value."
self.output_text['state'] = NORMAL
self.output_text.delete(1.0, END)
self.output_text.insert(END, value)
if self.encrypting and self.freeze_var.get():
self.output_text.see(END)
self.output_text['state'] = DISABLED
output = property(fset=output, doc='Output area property.')
@property
def chain_size(self):
"Chain size for the Markov chains used when encrypting."
try:
value = ast.literal_eval(self.chain_size_entry.get())
assert isinstance(value, int) and 2 <= value <= 256
return value
except:
self.chain_size_entry.delete(0, END)
self.chain_size_entry.insert(0, '2')
return 2
@property
def plain_text(self):
"Plain text or ignored characters in encryption process."
try:
value = self.repr_to_obj(self.plain_text_entry.get(), '')
assert isinstance(value, str)
return value
except:
self.plain_text_entry.delete(0, END)
return ''
########################################################################
# Encrypt a string for display in the interface's output area.
def encode(self, string):
"Encode the string and show the cipher-text in the output."
try:
cipher = self.build_cipher(string)
except ValueError:
self.output = ''
except:
self.output = traceback.format_exc()
else:
self.output = self.build_header() + '\n\n' + cipher
def build_cipher(self, string):
"Build cipher-text based on plain-text and return answer."
if self.key and self.freeze_var.get():
cipher, primer = me.encrypt_str(string, self.key, self.primer)
else:
args = string, self.chain_size, self.plain_text
cipher, self.key, self.primer = me.auto_encrypt_str(*args)
return cipher
def build_header(self):
"Build header from key and primer values in current use."
header = '\n'.join(map(self.bytes_to_repr, self.key.data))
header += '\n' + self.bytes_to_repr(self.primer.data)
return header
########################################################################
# Decrypt a string for display in the interface's output area.
def decode(self, string):
"Decode encrypted message and display plain-text in output."
try:
cipher = self.extract_keys(string)
text = self.extract_text(cipher)
except ValueError:
self.output = ''
except:
self.output = traceback.format_exc()
else:
self.output = text
def extract_keys(self, string):
"Extract keys to decryption and return the cipher-text area."
header, cipher = string.split('\n\n', 1)
*key, primer = map(self.repr_to_obj, header.split('\n'))
self.key, self.primer = me.Key(tuple(key)), me.Primer(primer)
return cipher
def extract_text(self, string):
"Extract text message from string using built key and primer."
text, primer = me.decrypt_str(string, self.key, self.primer)
return text
########################################################################
# Provide some special methods to simplify the program's code.
@property
def encrypting(self):
"Encrypting boolean stating current operations mode."
return {'encode': True, 'decode': False}[self.mode_var.get()]
@staticmethod
def bytes_to_repr(obj):
"Convert bytes object into suitable representation."
if not isinstance(obj, bytes):
raise TypeError('Object must be a bytes instance!')
return repr(obj)[2:-1]
@staticmethod
def repr_to_obj(string, prefix='b'):
"Convert representation into an equivalent object."
for template in '{}"{}"', "{}'{}'":
try:
return ast.literal_eval(template.format(prefix, string))
except:
pass
raise ValueError('Cannot convert {!r} to object!'.format(string))
@classmethod
def main(cls):
"Create context for demo and run a test instance."
NoDefaultRoot()
root = Tk()
root.minsize(420, 330)
root.title('Markov Demo 2')
test = cls(root)
test.grid(sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
################################################################################
# Start the demonstration if this module was run and not imported.
if __name__ == '__main__':
MarkovDemo.main()
|
The me
module can be found as recipe 578075.