Skip to content

Instantly share code, notes, and snippets.

@HacKanCuBa
Created September 26, 2019 00:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HacKanCuBa/bd6d5d0d049d7fc4900c6ebad44c2c91 to your computer and use it in GitHub Desktop.
Save HacKanCuBa/bd6d5d0d049d7fc4900c6ebad44c2c91 to your computer and use it in GitHub Desktop.
Python3 OTPCypher (toy module)
from typing import Tuple
from typing import Union
TParam = Union[bytes, str, bytearray]
class OTPCypher:
"""One-time pad cypher (use with extreme care!).
There are several restrictions for this to work: both parameters must have
the same byte length (meaning: be careful with non-ascii characters), and
the OTP parameter must truly be unique (if it is repeated, the encryption
can be broken). Additionally, no parameter must be controlled by the user
because this algorithm is malleable.
If that holds, then this encryption is information-theoretically secure.
"""
@staticmethod
def _check_param_before_conversion(param: TParam) -> bool:
if not isinstance(param, (bytes, str, bytearray)):
raise TypeError('Both parameters must be an instance of bytes, str or '
'bytearray')
return True
@classmethod
def _check_params_before_conversion(cls, p1: TParam, p2: TParam) -> bool:
return all((cls._check_param_before_conversion(p1),
cls._check_param_before_conversion(p2)))
@staticmethod
def _convert_param_to_process(param: TParam) -> bytearray:
if isinstance(param, str):
return bytearray(param, 'utf-8')
return bytearray(param)
@staticmethod
def _check_params_before_process(p1: bytearray, p2: bytearray) -> bool:
if not isinstance(p1, bytearray) or not isinstance(p2, bytearray):
raise TypeError('Both parameters must be an instance of bytearray')
if len(p1) != len(p2):
raise ValueError('Both parameters must be of the same length')
return True
@classmethod
def _convert_params_to_process(cls,
p1: TParam,
p2: TParam) -> Tuple[bytearray, bytearray]:
cls._check_params_before_conversion(p1, p2)
p1_c, p2_c = (cls._convert_param_to_process(p1),
cls._convert_param_to_process(p2))
cls._check_params_before_process(p1_c, p2_c)
return p1_c, p2_c
@staticmethod
def _convert_to_output(value: bytearray) -> str:
return value.decode('utf-8')
@classmethod
def encrypt_decrypt(cls, key: TParam, pt_ct: TParam) -> str:
"""Encrypt or decrypt given parameters.
:param key: Key parameter that will be used to encrypt or decrypt.
:param pt_ct: Either plain text to encrypt or cypher text to decrypt.
:return: The result of XORing each byte of both parameters, as UTF-8
string.
"""
# ToDo: maybe use a short header to know whether it's encrypted or not
key_p, pt_ct_p = cls._convert_params_to_process(key, pt_ct)
processed = bytearray(p1 ^ p2 for p1, p2 in zip(key_p, pt_ct_p))
return cls._convert_to_output(processed)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment