bgneal@65: M209 Class bgneal@65: ========== bgneal@65: bgneal@65: Naturally, the ``m209`` library includes a class that simulates a M-209 bgneal@65: converter. The :class:`~m209.converter.M209` class allows you to experiment bgneal@65: with all moving parts of an M-209, including encrypting and decrypting bgneal@69: messages. Keep in mind there is a higher level class, bgneal@69: :class:`~m209.procedure.StdProcedure`, that encapsulates all the steps of the bgneal@69: standard encrypting and decrypting operations, including generating indicators bgneal@69: and placing or removing them from messages. However if you need lower-level bgneal@69: access or you are inventing your own procedures, you would use the M209 class bgneal@69: directly. bgneal@65: bgneal@65: .. class:: m209.converter.M209([lugs=None[, pin_list=None]]) bgneal@65: bgneal@65: The ``M209`` class takes the following optional arguments. bgneal@65: bgneal@65: :param lugs: either a lug settings list or string as per :meth:`set_drum_lugs` bgneal@65: :param pin_list: a list of six strings each formatted as per :ref:`pin-settings` bgneal@65: bgneal@67: ``M209`` objects have the following attributes. bgneal@67: bgneal@67: .. attribute:: letter_count bgneal@67: bgneal@67: This attribute represents the *letter counter* functionality. It is an bgneal@67: integer that is incremented after every letter is encrypted or decrypted. bgneal@67: It may be set to any integer value or examined at any time. bgneal@67: bgneal@65: ``M209`` objects support the following methods. bgneal@65: bgneal@65: .. method:: set_pins(n, effective_pins) bgneal@65: bgneal@65: Sets the pin settings on the specified key wheel ``n``. bgneal@65: bgneal@65: :param n: an integer between 0-5, inclusive. Key wheel 0 is the bgneal@65: left-most wheel and wheel 5 is the right-most. bgneal@65: bgneal@65: :param effective_pins: an iterable of letters whose pins are slid to bgneal@65: the "effective" position (to the right). See :ref:`pin-settings`. bgneal@65: bgneal@65: .. method:: set_all_pins(pin_list) bgneal@65: bgneal@65: Sets all key wheel pins according to the supplied pin list. bgneal@65: bgneal@65: :param pin_list: must either be ``None`` or a 6-element list of strings bgneal@65: where each string element is as described in :ref:`pin-settings`. bgneal@65: If ``None``, all pins in all key wheels are moved to the ineffective position. bgneal@65: bgneal@65: .. method:: set_drum_lugs(lug_list) bgneal@65: bgneal@65: Sets the drum lugs according to the given ``lug_list`` parameter. bgneal@65: bgneal@65: If ``lug_list`` is ``None`` or empty, all lugs will be placed in neutral bgneal@65: positions. bgneal@65: bgneal@65: Otherwise, the ``lug_list`` can either be a list or a string. bgneal@65: bgneal@65: If ``lug_list`` is passed a list, it must be a list of 1 or 2-tuple integers, bgneal@65: where each integer is between 0-5, inclusive, and represents a 0-based bgneal@65: key wheel position. The list can not be longer than 27 items. Only lug bgneal@65: bars with lugs in non-neutral positions need be listed. Lug bars with one bgneal@65: lug in a non-neutral position are represented by a 1-tuple. Bars with bgneal@65: 2 non-netural lugs are represented as a 2-tuple. bgneal@65: bgneal@65: If ``lug_list`` is passed as a string, it is assumed to be in key list bgneal@65: format as described in :ref:`lug-settings`. bgneal@65: bgneal@65: Example:: bgneal@65: bgneal@65: m = M209() bgneal@65: m.set_drum_lugs('1-0 2-0*2 0-3 0-5*3 0-6 2-4 3-6') bgneal@65: bgneal@65: # or equivalently bgneal@65: m.set_drum_lugs([(0, ), (1, ), (1, ), (2, ), (4, ), (4, ), (4, ), (5, ), (1, 3), (2, 5)]) bgneal@65: bgneal@65: bgneal@65: .. method:: set_key_wheel(n, c) bgneal@65: bgneal@65: Set key wheel ``n`` to the letter ``c``. bgneal@65: bgneal@65: :param n: an integer between 0-5 where key wheel 0 is the leftmost key wheel, bgneal@65: and 5 is the rightmost bgneal@65: :param c: a 1-letter string valid for key wheel ``n`` bgneal@65: :raises KeyWheelError: if ``c`` is not valid for wheel ``n`` bgneal@65: bgneal@65: .. method:: set_key_wheels(s) bgneal@65: bgneal@65: Set the key wheels from left to right to the six letter string ``s``. bgneal@65: bgneal@65: :raises KeyWheelError: if any letter in ``s`` is not valid for the corresponding key wheel bgneal@65: bgneal@65: .. method:: set_random_key_wheels() bgneal@65: bgneal@65: Sets the six key wheels to random letters. bgneal@65: bgneal@65: :returns: a string of length six representing the new key wheel settings bgneal@65: bgneal@65: .. method:: get_settings() bgneal@65: bgneal@65: Returns the current key settings. bgneal@65: bgneal@65: :returns: a named tuple of ``(lugs, pin_list)`` representing the current bgneal@65: key settings. ``lugs`` will be in string format. bgneal@65: bgneal@65: .. method:: encrypt(plaintext[, group=True[, spaces=True]]) bgneal@65: bgneal@65: Performs an encrypt operation on the given plaintext and returns the bgneal@65: encrypted ciphertext as a string. bgneal@65: bgneal@65: :param plaintext: the text string to encrypt bgneal@65: :param group: if ``True``, the ciphertext string will be grouped into 5-letter bgneal@65: groups, separated by spaces bgneal@65: :param spaces: if ``True``, space characters in the input plaintext will bgneal@65: automatically be treated as ``Z`` characters. Otherwise spaces in the bgneal@65: plaintext will raise an ``M209Error``. bgneal@65: :returns: the ciphertext as a string bgneal@65: bgneal@65: .. method:: decrypt(ciphertext[, spaces=True[, z_sub=True]]) bgneal@65: bgneal@65: Performs a decrypt operation on the given ciphertext and returns the bgneal@65: decrypted plaintext as a string. bgneal@65: bgneal@65: :param ciphertext: the text string to decyrpt bgneal@65: :param spaces: if ``True``, spaces will be allowed in the input ciphertext and bgneal@65: ignored. Otherwise space characters will raise an ``M209Error``. bgneal@65: This is useful if the input ciphertext is in 5-letter groups, separated bgneal@65: by spaces. bgneal@65: :param z_sub: if ``True``, ``Z`` characters in the output plaintext will be bgneal@65: replaced by space characters, just like an actual M-209. bgneal@65: :returns: the plaintext as a string bgneal@65: bgneal@65: Example: bgneal@65: bgneal@65: >>> from m209.converter import M209 bgneal@65: >>> m = M209() bgneal@65: >>> m.set_drum_lugs('1-0 2-0*2 0-3 0-5*3 0-6 2-4 3-6') bgneal@65: >>> pin_list = [ bgneal@65: ... 'FGIKOPRSUVWYZ', bgneal@65: ... 'DFGKLMOTUY', bgneal@65: ... 'ADEFGIORTUVX', bgneal@65: ... 'ACFGHILMRSU', bgneal@65: ... 'BCDEFJKLPS', bgneal@65: ... 'EFGHIJLMNP' bgneal@65: ... ] bgneal@65: >>> m.set_all_pins(pin_list) bgneal@65: >>> m.set_key_wheels('FFEGJP') bgneal@65: >>> ct = m.encrypt('THE PIZZA HAS ARRIVED') bgneal@65: >>> ct bgneal@65: 'QBCHU WCCDI YFNCH LOZJY G' bgneal@65: >>> m.set_key_wheels('FFEGJP') bgneal@65: >>> pt = m.decrypt(ct) bgneal@65: >>> pt bgneal@65: 'THE PI A HAS ARRIVED'