diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f830b12 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,27 @@ +# License + +***ROTate*** - Encryption tool based on the ROT cipher + +Copyright © 2018 by Ralf Kilian + +Distributed under the *MIT License*: + +``` +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/README.md b/README.md new file mode 100644 index 0000000..cee5e83 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# *ROTate* ROTate logo + +**Table of contents** + +* [Definition](#definition) +* [Details](#details) +* [Components](#components) +* [Requirements](#requirements) +* [Documentation](#documentation) +* [Useless facts](#useless-facts) + +---- + +## Definition + +The *ROTate* project is a collection of scripts to encrypt and decrypt files using various *ROT* cipher methods. + +[Top](#) + +## Details + +The project allows to encrypt and decrypt files using various ROT cipher methods such as *ROT13*, *ROT47*, *ROT128* as well as with enhanced variants based on each character set of these methods. + +It also comes with a tool to find out which variant and value has been used to encrypt a file. + +Due to the fact, that data encrypted with *ROT* methods can be cracked quite easily, they are **not** suitable for encrypting sensible data. + +[Top](#) + +## Components + +### *ROTate* variants + +There are three components to encrypt and decrypt files using the *ROT13*, *ROT47* and *ROT128* cipher method. + +They also allow using a user-defined rotation value (based on the character set of that cipher method) instead of the default rotation value. + +### *ROTate Cracker* + +As already mentioned above, data encrypted with *ROT* methods can be cracked quite easily. This brute force cracker helps to determine which *ROT* variant and rotation value has been used to encrypt a file or string by simply trying all supported variants with all rotation values available. + +[Top](#) + +## Requirements + +In order to use *ROTate*, the *Python* framework must be installed on the system. + +Depending on which version of the framework you are using: + +* *Python* 2.x (version 2.7 or higher is recommended, may also work with earlier versions) +* *Python* 3.x (version 3.2 or higher is recommended, may also work with earlier versions) + +[Top](#) + +## Documentation + +In the corresponding `docs` sub-directories, there are plain text files containing a detailed documentation for each component with further information and usage examples. + +[Top](#) + +## Useless facts + +* The name *ROTate* stands for ***ROT*** *with* ***A**dditional* ***T**ools* *and* ***E**nhancements*. +* The first version uploaded on *GitHub* was *ROTate* 3.0.6 built on March 13th, 2018. +* Before uploading, the project has neither been changed nor even touched for more than three years. + +[Top](#) diff --git a/python2/changelog.txt b/python2/changelog.txt new file mode 100644 index 0000000..c5739f6 --- /dev/null +++ b/python2/changelog.txt @@ -0,0 +1,57 @@ + +CHANGELOG (ROTate) + + Version 3.0.6 (2018-03-13) + + + Added new versions of the Clap and PaVal core modules (replaced the + existing ones). + + * Revised (refurbished) all components of the project in general + (neglibible changes). + + # Fixed the wildcard bug (certain characters inside the strings to + encrypt and decrypt and will no longer be interpreted as wildcards). + + Version 3.0.5 (2015-01-03) + + * Revised some code inside the ROTate Cracker core module (negligible + changes). + + - Removed unnecessary module imports from the core modules. + + Version 3.0.4 (2014-04-03) + + + Added an optional command-line argument to the ROTate Cracker script + to write the integer ordinals of the decrypted string into the + output file. + + Version 3.0.3 (2014-03-21) + + * Revised (reduced) some code inside the ROTate Cracker core module. + * Revised the ROTate Cracker output file (non-printable characters are + now replaced either with whitespaces or a corresponding notice). + + # Fixed the attribute error inside the ROTate Cracker core module when + reading out the major version of the Python framework using Python + version 2.6 or below. + + Version 3.0.2 (2014-03-14) + + + Added an error handler to the ROTate scripts in case no command-line + argument parser can be initialized. + + * Revised (reduced) some code inside the ROTate Cracker core module. + * Revised the transform methods inside the ROT13, ROT47 and ROT128 + core module (reduced some code for increased readability). + + Version 3.0.1 (2014-03-07) + + * Revised the description of some command-line arguments inside all + ROTate scripts. + * Revised the header of the ROTate Cracker output file (negligible + text changes). + + Version 3.0.0 (2014-02-11) + + * First official release of this major version. + diff --git a/python2/core/__init__.py b/python2/core/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/python2/core/clap.py b/python2/core/clap.py new file mode 100755 index 0000000..03305c0 --- /dev/null +++ b/python2/core/clap.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# Clap - Command-line argument parser module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/clap +# ============================================================================ + +__version__ = "1.1.10" + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +class Parser(object): + """ + Project independent command-line argument parser class. + """ + __arg_grp_opt = None + __arg_grp_req = None + __arg_parser = None + __is_argparser = False + __conflict_handler = "resolve" # used by OptionParser, only + + def __init__(self): + try: + from argparse import ArgumentParser + self.__arg_parser = ArgumentParser(add_help=False) + self.__arg_grp_req = \ + self.__arg_parser.add_argument_group("required arguments") + self.__arg_grp_opt = \ + self.__arg_parser.add_argument_group("optional arguments") + self.__is_argparser = True + return + except ImportError: + # Ignore the exception and proceed with the fallback + pass + + try: + from optparse import OptionParser + self.__arg_parser = \ + OptionParser(conflict_handler=self.__conflict_handler) + self.__arg_grp_req = \ + self.__arg_parser.add_option_group("Required arguments") + self.__arg_grp_opt = \ + self.__arg_parser.add_option_group("Optional arguments") + return + except ImportError: + # This should never happen + raise ImportError("Failed to initialize an argument parser.") + + def add_avalue(self, arg_short, arg_long, arg_help, arg_dest, arg_default, + arg_required): + """ + Add an argument that expects a single user-defined value. + """ + if arg_required: + obj = self.__arg_grp_req + else: + obj = self.__arg_grp_opt + + if arg_default is not None: + # Enclose the value with quotes in case it is not an integer + quotes = "'" + try: + arg_default = int(arg_default) + quotes = "" + except ValueError: + pass + + if arg_help.strip().endswith(")"): + arg_help = arg_help.rstrip(")") + arg_help += ", default is %s%s%s)" % \ + (quotes, str(arg_default), quotes) + else: + arg_help += " (default is %s%s%s)" % \ + (quotes, str(arg_default), quotes) + + if self.__is_argparser: + if arg_short is None: + obj.add_argument(arg_long, help=arg_help, dest=arg_dest, + default=arg_default, required=arg_required) + else: + obj.add_argument(arg_short, arg_long, help=arg_help, + dest=arg_dest, default=arg_default, + required=arg_required) + else: + if arg_short is None: + obj.add_option(arg_long, help=arg_help, dest=arg_dest, + default=arg_default) + else: + obj.add_option(arg_short, arg_long, help=arg_help, + dest=arg_dest, default=arg_default) + + def add_predef(self, arg_short, arg_long, arg_help, arg_dest, arg_choices, + arg_required): + """ + Add an argument that expects a certain predefined value. + """ + if arg_required: + obj = self.__arg_grp_req + else: + obj = self.__arg_grp_opt + + if self.__is_argparser: + if arg_short is None: + obj.add_argument(arg_long, help=arg_help, dest=arg_dest, + choices=arg_choices, required=arg_required) + else: + obj.add_argument(arg_short, arg_long, help=arg_help, + dest=arg_dest, choices=arg_choices, + required=arg_required) + else: + if arg_short is None: + obj.add_option(arg_long, help=arg_help, dest=arg_dest, + choices=arg_choices) + else: + # The OptionParser does not print the values to choose from, + # so these have to be added manually to the description of + # the argument first + arg_help += " (choose from " + for item in arg_choices: + arg_help += "'%s', " % item + arg_help = arg_help.rstrip(", ") + ")" + + obj.add_option(arg_short, arg_long, help=arg_help, + dest=arg_dest) + + def add_switch(self, arg_short, arg_long, arg_help, arg_dest, arg_store, + arg_required): + """ + Add an argument that does not expect anything, but returns a + boolean value. + """ + if arg_required: + obj = self.__arg_grp_req + else: + obj = self.__arg_grp_opt + + if arg_store: + arg_store = "store_true" + else: + arg_store = "store_false" + + if self.__is_argparser: + if arg_short is None: + obj.add_argument(arg_long, help=arg_help, dest=arg_dest, + action=arg_store, required=arg_required) + else: + obj.add_argument(arg_short, arg_long, help=arg_help, + dest=arg_dest, action=arg_store, + required=arg_required) + else: + if arg_short is None: + obj.add_option(arg_long, help=arg_help, dest=arg_dest, + action=arg_store) + else: + obj.add_option(arg_short, arg_long, help=arg_help, + dest=arg_dest, action=arg_store) + + def dependency(self, arg_name, arg_value, dependency): + """ + Check the dependency of a command-line argument. + """ + if dependency is not None: + if arg_value is None or str(arg_value) == "": + raise Exception("The '%s' argument depends on %s'." % + (arg_name, dependency)) + + def error(self, obj): + """ + Raise an error and cause the argument parser to print the error + message. + """ + if type(obj) == str: + obj = obj.strip() + + self.__arg_parser.error(obj) + + def parse_args(self): + """ + Parse and return the command-line arguments. + """ + if self.__is_argparser: + args = self.__arg_parser.parse_args() + else: + (args, values) = self.__arg_parser.parse_args() + return args + + def print_help(self): + """ + Print the usage, description, argument details and epilog. + """ + self.__arg_parser.print_help() + + def set_description(self, string): + """ + Set the description text. + """ + self.__arg_parser.description = string.strip() + + def set_epilog(self, string): + """ + Set the epilog text. + """ + self.__arg_parser.epilog = string.strip() + +# EOF diff --git a/python2/core/common.py b/python2/core/common.py new file mode 100755 index 0000000..4342ab4 --- /dev/null +++ b/python2/core/common.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# Common core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +import paval as pv + + +def get_file_size(file_path): + """ + Get the size of a file in bytes. + """ + pv.path(file_path, "", True, True) + + f = open(file_path, "rb") + f.seek(0, 2) + file_size = f.tell() + f.close() + + return int(file_size) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + +# EOF diff --git a/python2/core/cracker.py b/python2/core/cracker.py new file mode 100755 index 0000000..6fd937f --- /dev/null +++ b/python2/core/cracker.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# Cracker core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +import os +import paval as pv +import rot13 +import rot47 +import rot128 +import string as st +import sys + +from datetime import datetime as dt + + +def brute_force(string, file_output, method=None, int_ordinals=False, + non_printable=False, limit=True): + """ + Brute-force the given string to find out which ROT variant and + rotation value was used to encrypt. + """ + pv.path(file_output, "output", True, False) + pv.string(string, "string to decrypt", True) + file_output = os.path.abspath(file_output) + + if method is None: + method = "All" + else: + method = method.upper() + pv.compstr(method, "method", ["ROT13", "ROT47", "ROT128"]) + + list_values_rot13 = [] + list_values_rot47 = [] + list_values_rot128 = [] + timestamp = str(dt.now()) + output = "\r\n" + "=" * 78 + \ + "\r\nFile type: ROTate Cracker output file" \ + "\r\n" + "-" * 78 + \ + "\r\nOutput file name: " + file_output + \ + "\r\nString to decrypt: " + string + \ + "\r\nMethods used: " + method + \ + "\r\n" + "-" * 78 + \ + "\r\nTimestamp: " + timestamp[:-7] + \ + "\r\nROTate version: " + get_version() + \ + "\r\n" + "=" * 78 + "\r\n\r\n" + + if method == "All" or method == "ROT13": + list_values_rot13 = \ + __get_values_rot13(string, int_ordinals, non_printable, limit) + if method == "All" or method == "ROT47": + list_values_rot47 = \ + __get_values_rot47(string, int_ordinals, non_printable, limit) + if method == "All" or method == "ROT128": + list_values_rot128 = \ + __get_values_rot128(string, int_ordinals, non_printable, limit) + + if len(list_values_rot13) > 0: + output += "\r\n [ROT13]\r\n" + for value in list_values_rot13: + output += " - %s\r\n" % value + output += "\r\n" + if len(list_values_rot47) > 0: + output += "\r\n [ROT47]\r\n" + for value in list_values_rot47: + output += " - %s\r\n" % value + output += "\r\n" + if len(list_values_rot128) > 0: + output += "\r\n [ROT128]\r\n" + for value in list_values_rot128: + output += " - %s\r\n" % value + output += "\r\n" + fh_output = open(file_output, "wb") + + # Run the appropriate code for the Python framework used + if sys.version_info[0] == 2: + fh_output.write(output) + elif sys.version_info[0] > 2: + fh_output.write(output.encode(sys.getdefaultencoding())) + + fh_output.close() + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __get_int_ordinals(string): + """ + Return the integer ordinals of a string. + """ + output = "" + + for char in string: + output += str(ord(char)).rjust(3, " ") + ", " + output = output.rstrip(", ") + + return output + + +def __get_printable(string): + """ + Replace non-printable characters inside a string with whitespaces + """ + output = "" + + chars_remove = "\t\n\r\x0b\x0c" + for char in chars_remove: + string = string.replace(char, " ") + + for char in string: + if char not in st.printable: + output += " " + else: + output += char + + if output.strip() == "": + output = "(only non-printable characters or spaces)" + + return output + + +def __get_values_rot13(string, int_ordinals, non_printable, limit): + """ + Core method to get all possible ROT13 values for the given string. + """ + list_values = [] + for i in range(1, 26): + output = __prepare_line(rot13.decrypt_string(string, i), + int_ordinals, non_printable, limit) + list_values.append("Value %s: %s" % (str(i).rjust(3, " "), output)) + + return list_values + + +def __get_values_rot47(string, int_ordinals, non_printable, limit): + """ + Core method to get all possible ROT47 values for the given string. + """ + list_values = [] + for i in range(1, 94): + output = __prepare_line(rot47.decrypt_string(string, i), + int_ordinals, non_printable, limit) + list_values.append("Value %s: %s" % (str(i).rjust(3, " "), output)) + + return list_values + + +def __get_values_rot128(string, int_ordinals, non_printable, limit): + """ + Core method to get all possible ROT128 values for the given string. + """ + list_values = [] + for i in range(1, 256): + output = __prepare_line(rot128.decrypt_string(string, i), + int_ordinals, non_printable, limit) + list_values.append("Value %s: %s" % (str(i).rjust(3, " "), output)) + + return list_values + + +def __prepare_line(line, int_ordinals, non_printable, limit): + """ + Prepare the line before it gets written into the file. + """ + if int_ordinals: + line = __get_int_ordinals(line) + else: + if not non_printable: + line = __get_printable(line) + + if limit: + if len(line) > 58: + line = line[:55] + "..." + + return line + +# EOF diff --git a/python2/core/paval.py b/python2/core/paval.py new file mode 100755 index 0000000..a2ed54a --- /dev/null +++ b/python2/core/paval.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# PaVal - Parameter validation module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/paval +# ============================================================================ + +__version__ = "1.2.7" + +import filecmp +import os + + +def compfile(path, name="", list_files=[]): + """ + Compare files to avoid that the same file is given multiple times or + in different ways (e. g. different name but same content). + """ + __string(path, "%s path" % name, True) + + if list_files is None: + list_files = [] + elif len(list_files) == 0: + __ex("File list is empty (no files to compare with).", True) + else: + for item in list_files: + if not type(item) == list: + __ex("Every list item must be a sub-list.", True) + if not len(item) == 2: + __ex("Every sub-list must contain two items.", True) + + path = os.path.abspath(path) + for item in list_files: + path_compare = os.path.abspath(str(item[0])) + name_compare = str(item[1]) + if path == path_compare: + __ex("The %s and the %s file path must not be identical." % + (name, name_compare), False) + if os.path.exists(path) and os.path.exists(path_compare): + if filecmp.cmp(path, path_compare, 0): + __ex("The %s and %s file content must not be identical." % + (name, name_compare), False) + + +def compstr(string, name="", list_strings=[]): + """ + Compare a string with a list of strings and check if it is an item of + that list. + """ + __string(string, name, False) + if len(list_strings) == 0: + __ex("No %s strings to compare with." % name, True) + if string not in list_strings: + __ex("The %s '%s' does not exist." % (name, string), False) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def intrange(value, name="", value_min=None, value_max=None, zero=False): + """ + Validate an integer range. + """ + value = __integer(value, "%s value" % name, False) + if value_min is not None: + value_min = __integer(value_min, "minimal %s value" % name, True) + intvalue(value_min, name, True, True, True) + if value_max is not None: + value_max = __integer(value_max, "maximal %s value" % name, True) + intvalue(value_max, name, True, True, True) + if not zero: + if value == 0: + __ex("The %s value must not be zero." % name, False) + if (value_min is not None) and (value_max is not None): + if value_min > value_max: + __ex("The maximal %s value must be greater than the minimal " + "value." % name, False) + if (value_min == value_max) and (not value == value_min): + __ex("The %s value can only be %s (depending on further range " + "further range arguments)." % (name, value_min), False) + if (value < value_min) or (value > value_max): + __ex("The %s value must be between %s and %s (depending on " + "further range arguments)." % (name, value_min, value_max), + False) + elif value_min is not None: + if value < value_min: + __ex("The %s value must not be less than %s." % (name, value_min), + False) + elif value_max is not None: + if value > value_max: + __ex("The %s value must not be greater than %s." % + (name, value_max), False) + + +def intvalue(value, name="", positive=True, zero=False, negative=False): + """ + Validate a single integer value. + """ + value = __integer(value, "%s value" % name, False) + if not positive: + if value > 0: + __ex("The %s value must not be positive." % name, False) + if not zero: + if value == 0: + __ex("The %s value must not be zero." % name, False) + if not negative: + if value < 0: + __ex("The %s value must not be negative." % name, False) + + +def path(path, name="", is_file=False, exists=False): + """ + Validate a path of a file or directory. + """ + string(path, "%s path" % name, False, None) + path = os.path.abspath(path) + + if is_file: + path_type = "file" + else: + path_type = "directory" + if exists: + if not os.path.exists(path): + __ex("The given %s %s does not exist." % (name, path_type), False) + if (is_file and not os.path.isfile(path)) or \ + (not is_file and not os.path.isdir(path)): + __ex("The given %s %s path is not a %s." % (name, path_type, + path_type), False) + else: + if os.path.exists(path): + __ex("The given %s %s path already exists." % (name, path_type), + False) + + +def string(string, name="", wildcards=False, invalid_chars=None): + """ + Validate a string. + """ + __string(string, name, False) + if invalid_chars is None: + invalid_chars = "" + if not wildcards: + if ("*" in string) or ("?" in string): + __ex("The %s must not contain wildcards." % name, False) + if len(invalid_chars) > 0: + for char in invalid_chars: + if char in string: + # Use single quotes by default or double quotes in case the + # single quotes are the invalid character + quotes = "'" + if char == quotes: + quotes = "\"" + + __ex("The %s contains at least one invalid character " + "(%s%s%s)." % (name, quotes, char, quotes), False) + + +def __ex(string, internal=False): + """ + Internal method to raise an exception. + """ + string = str(string).strip() + while (" " * 2) in string: + string = string.replace((" " * 2), " ") + if internal: + string = "PaVal: " + string + raise Exception(string) + + +def __integer(value, name="", internal=False): + """ + Internal method for basic integer validation. + """ + if value is None: + __ex("The %s is missing." % name, internal) + if value == "": + __ex("The %s must not be empty." % name, internal) + try: + value = int(value) + except ValueError: + __ex("The %s must be an integer." % name, internal) + return int(value) + + +def __string(string, name="", internal=False): + """ + Internal method for basic string validation. + """ + if string is None: + __ex("The %s is missing." % name, internal) + if string == "": + __ex("The %s must not be empty." % name, internal) + +# EOF diff --git a/python2/core/rot128.py b/python2/core/rot128.py new file mode 100755 index 0000000..b3a5265 --- /dev/null +++ b/python2/core/rot128.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT128 encryption/decryption core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +import common +import os +import paval as pv + + +def encrypt_file(file_input, file_output, buffer_size=4096, rot_value=128): + """ + Encrypt a file using ROT128. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def encrypt_string(string, rot_value): + """ + Encrypt a string using ROT128. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(True, string, rot_value) + + +def decrypt_file(file_input, file_output, buffer_size=4096, rot_value=128): + """ + Decrypt a file using ROT128. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def decrypt_string(string, rot_value): + """ + Decrypt a string using ROT128. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(False, string, rot_value) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __transform_bytes(encrypt, data_input, rot_value): + """ + Core method to manipulate bytes. + """ + data_output = bytearray(b"") + + for byte in data_input: + if encrypt: + data_output.append(((byte + rot_value) % 256)) + else: + data_output.append(((byte - rot_value) % 256)) + + return data_output + + +def __transform_string(encrypt, string, rot_value): + """ + Core method to manipulate a string. + """ + output = "" + + for char in string: + if encrypt: + output += chr(((ord(char) + rot_value) % 256)) + else: + output += chr(((ord(char) + rot_value) % 256)) + + return output + +# EOF diff --git a/python2/core/rot13.py b/python2/core/rot13.py new file mode 100755 index 0000000..ac0120b --- /dev/null +++ b/python2/core/rot13.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT13 encryption/decryption core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +import common +import os +import paval as pv + + +def encrypt_file(file_input, file_output, buffer_size=4096, rot_value=13): + """ + Encrypt a file using ROT13. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def encrypt_string(string, rot_value=13): + """ + Encrypt a string using ROT13. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(True, string, rot_value) + + +def decrypt_file(file_input, file_output, buffer_size=4096, rot_value=13): + """ + Decrypt a file using ROT13. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def decrypt_string(string, rot_value=13): + """ + Decrypt a string using ROT13. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(False, string, rot_value) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __transform_bytes(encrypt, data_input, rot_value): + """ + Core method to manipulate bytes. + """ + data_output = bytearray(b"") + + for byte in data_input: + if byte in range(65, 91): + # Uppercase letters + if encrypt: + data_output.append((((byte - 65) + rot_value) % 26) + 65) + else: + data_output.append((((byte - 65) - rot_value) % 26) + 65) + elif byte in range(97, 123): + # Lowercase letters + if encrypt: + data_output.append((((byte - 97) + rot_value) % 26) + 97) + else: + data_output.append((((byte - 97) - rot_value) % 26) + 97) + else: + data_output.append(byte) + + return data_output + + +def __transform_string(encrypt, string, rot_value): + """ + Core method to manipulate a string. + """ + output = "" + + for char in string: + if ord(char) in range(65, 91): + # Uppercase letters + if encrypt: + output += chr((((ord(char) - 65) + rot_value) % 26) + 65) + else: + output += chr((((ord(char) - 65) - rot_value) % 26) + 65) + elif ord(char) in range(97, 123): + # Lowercase letters + if encrypt: + output += chr((((ord(char) - 97) + rot_value) % 26) + 97) + else: + output += chr((((ord(char) - 97) - rot_value) % 26) + 97) + else: + output += char + + return output + +# EOF diff --git a/python2/core/rot47.py b/python2/core/rot47.py new file mode 100755 index 0000000..ee71aef --- /dev/null +++ b/python2/core/rot47.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT47 encryption/decryption core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +import common +import os +import paval as pv + + +def encrypt_file(file_input, file_output, buffer_size=4096, rot_value=47): + """ + Encrypt a file using ROT47. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def encrypt_string(string, rot_value=47): + """ + Encrypt a string using ROT47. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(True, string, rot_value) + + +def decrypt_file(file_input, file_output, buffer_size=4096, rot_value=47): + """ + Decrypt a file using ROT47. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def decrypt_string(string, rot_value=47): + """ + Decrypt a string using ROT47. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(False, string, rot_value) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __transform_bytes(encrypt, data_input, rot_value): + """ + Core method to manipulate bytes. + """ + data_output = bytearray(b"") + + for byte in data_input: + if byte in range(32, 126): + if encrypt: + data_output.append((((byte - 32) + rot_value) % 94) + 32) + else: + data_output.append((((byte - 32) - rot_value) % 94) + 32) + else: + data_output.append(byte) + + return data_output + + +def __transform_string(encrypt, string, rot_value): + """ + Core method to manipulate a string. + """ + output = "" + + for char in string: + if ord(char) in range(32, 126): + if encrypt: + output += chr((((ord(char) - 32) + rot_value) % 94) + 32) + else: + output += chr((((ord(char) - 32) - rot_value) % 94) + 32) + else: + output += char + + return output + +# EOF diff --git a/python2/docs/usage_rotate-cracker.txt b/python2/docs/usage_rotate-cracker.txt new file mode 100644 index 0000000..60c548f --- /dev/null +++ b/python2/docs/usage_rotate-cracker.txt @@ -0,0 +1,83 @@ + +USAGE (rotate-cracker.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Crack a ROT encrypted file + + 1. Definition + + The ROTate Cracker script helps to determine which ROT variant and + rotation value was used to encrypt a file or string by trying all + supported ROT variants with all rotation values available (brute + force). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-cracker.py --help + + 3. Crack a ROT encrypted file + + For example, you have the ROT encrypted file "secret.txt" containing + the line + + Uryyb, Jbeyq! + + and want to decrypt it. So, to find out which ROT method and rotation + value was used to encrypt the file, a string from the file (e. g. a + word) is required. + + This example uses the string "Uryyb" and writes the decrypted values + into the file "/tmp/output.txt": + + $ ./rotate-cracker.py -s "Uryyb" -o /tmp/output.txt + + The output file shows that when using the ROT13 method, the string + "Uryyb" decrypted with value 13 returns the word "Hello": + + (...) + [ROT13] + - Value 0: Uryyb + - Value 1: Tqxxa + - Value 2: Spwwz + - Value 3: Rovvy + - Value 4: Qnuux + - Value 5: Pmttw + - Value 6: Olssv + - Value 7: Nkrru + - Value 8: Mjqqt + - Value 9: Lipps + - Value 10: Khoor + - Value 11: Jgnnq + - Value 12: Ifmmp + - Value 13: Hello + (...) + + So, the file or at least that string seems to be encrypted with that + method and value. Unfortunately, there is no analysis feature, which + means you will have to look at the returned value list to manually + check which entry makes most sense. + + If there are non-printable characters inside the string, they will be + replaced by whitespaces. If the string only contains of whitespaces, + a notice will be written to the output file. + diff --git a/python2/docs/usage_rotate-rot128.txt b/python2/docs/usage_rotate-rot128.txt new file mode 100644 index 0000000..53b835d --- /dev/null +++ b/python2/docs/usage_rotate-rot128.txt @@ -0,0 +1,56 @@ + +USAGE (rotate-rot128.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Encrypt a file + 4. Decrypt the file again + 5. User-defined rotation values + + 1. Definition + + The ROTate ROT128 script encrypts and decrypts a file using the ROT128 + method with the default rotation value or a user-defined one (using + the ROT128 character set). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-rot128.py --help + + 3. Encrypt a file + + This works as described in section 3 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT128 instead of the + script used there. + + 4. Decrypt the file again + + This works as described in section 4 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT128 instead of the + script used there. + + 5. User-defined rotation values + + This works as described in section 5 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT128 instead of the + script used there. + diff --git a/python2/docs/usage_rotate-rot13.txt b/python2/docs/usage_rotate-rot13.txt new file mode 100644 index 0000000..918322b --- /dev/null +++ b/python2/docs/usage_rotate-rot13.txt @@ -0,0 +1,74 @@ + +USAGE (rotate-rot13.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Encrypt a file + 4. Decrypt the file again + 5. User-defined rotation values + + 1. Definition + + The ROTate ROT13 script encrypts and decrypts a file using the ROT13 + method with the default rotation value or a user-defined one (using + the ROT13 character set). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-rot13.py --help + + 3. Encrypt a file + + For example, if you have the input file "hello.txt" containing the + line + + Hello, world! + + and want to encrypt it using ROT13 (with its default value) and write + the encrypted data into "secret.txt", the command line would look like + this: + + $ ./rotate-rot13.py -i hello.txt -o secret.txt -a encrypt + + The encrypted data inside "secret.txt" should look like this: + + Uryyb, Jbeyq! + + 4. Decrypt the file again + + To decrypt the file again and write the decrypted data into the file + "output.txt", type: + + $ ./rotate-rot13.py -i secret.txt -o output.txt -a decrypt + + 5. User-defined rotation values + + You can also encrypt the file using the ROT13 method, but with + rotation value 19 instead of the default value: + + $ ./rotate-rot13.py -i hello.txt -o secret.txt -a encrypt -v 19 + + The user-defined rotation value used to encrypt is also required to + properly decrypt the file again: + + $ ./rotate-rot13.py -i secret.txt -o output.txt -a decrypt -v 19 + diff --git a/python2/docs/usage_rotate-rot47.txt b/python2/docs/usage_rotate-rot47.txt new file mode 100644 index 0000000..1498be1 --- /dev/null +++ b/python2/docs/usage_rotate-rot47.txt @@ -0,0 +1,56 @@ + +USAGE (rotate-rot47.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Encrypt a file + 4. Decrypt the file again + 5. User-defined rotation values + + 1. Definition + + The ROTate ROT47 script encrypts and decrypts a file using the ROT47 + method with the default rotation value or a user-defined one (using + the ROT47 character set). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-rot47.py --help + + 3. Encrypt a file + + This works as described in section 3 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT47 instead of the script + used there. + + 4. Decrypt the file again + + This works as described in section 4 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT47 instead of the script + used there. + + 5. User-defined rotation values + + This works as described in section 5 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT47 instead of the script + used there. + diff --git a/python2/license.txt b/python2/license.txt new file mode 100644 index 0000000..6f15220 --- /dev/null +++ b/python2/license.txt @@ -0,0 +1,27 @@ + +LICENSE (ROTate) + + ROTate - Encryption tool based on the ROT cipher + Copyright (C) 2018 by Ralf Kilian + + Distributed under the MIT License: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/python2/readme.txt b/python2/readme.txt new file mode 100644 index 0000000..e643f41 --- /dev/null +++ b/python2/readme.txt @@ -0,0 +1,49 @@ + +README (ROTate) + + Project + + ROTate + Version 3.0.6 (based on Python framework 2.x) + Copyright (C) 2018 by Ralf Kilian + + Website: http://www.urbanware.org + GitHub: https://github.com/urbanware-org/rotate + + Definition + + The ROTate project is a collection of scripts to encrypt and decrypt + files using various ROT cipher methods. + + License + + This project is distributed under the MIT License. You should have + received a copy of the license along with this program (see the + 'license.txt' file). If not, you can find the license terms here: + + https://opensource.org/licenses/MIT + + Requirements + + The requirements for this project can be found inside the included + file 'requirements.txt'. + + In case this file is missing, you can also find the information on the + website of the project mentioned above. + + Usage + + For fundamental documentation as well as some usage examples for each + component of the project, you may have a look at the text files inside + the included 'docs' sub-directory. + + Legal information + + The project name is completely fictitious. Any correspondences with + existing websites, applications, companies and/or other projects are + purely coincidental. + + All trademarks belong to their respective owners. + + Errors and omissions excepted. + diff --git a/python2/requirements.txt b/python2/requirements.txt new file mode 100644 index 0000000..3d50015 --- /dev/null +++ b/python2/requirements.txt @@ -0,0 +1,17 @@ + +REQUIREMENTS (ROTate) + + Notice + + This version of ROTate was built for the Python 2.x framework. If you + need a version that works with Python 3.x, you may look here: + + http://www.urbanware.org/rotate.html + + General + + Software requirements: + + - Python 2.x (version 2.7 or higher is recommended, may also work + with earlier versions) + diff --git a/python2/rotate-cracker.py b/python2/rotate-cracker.py new file mode 100755 index 0000000..ba99fb6 --- /dev/null +++ b/python2/rotate-cracker.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# Cracker script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import cracker + + try: + p = clap.Parser() + except Exception as e: + print "%s: error: %s" % (os.path.basename(sys.argv[0]), e) + sys.exit(1) + + p.set_description("Determine which ROT variant and rotation value was " + "used to encrypt a file or string by trying all " + "supported ROT variants with all rotation values " + "available (brute force).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + p.add_avalue("-s", "--string", "string to decrypt", "string", None, True) + + # Define optional arguments + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_switch(None, "--int-ordinals", "write integer ordinals instead " + "of the characters into the output file", "int_ordinals", + True, False) + p.add_predef("-m", "--method", "use only one instead of all supported " + "methods to decrypt", "method", ["rot13", "rot47", "rot128"], + False) + p.add_switch(None, "--no-limit", "do not limit the length of the lines " + "inside the output file", "no_limit", False, False) + p.add_switch(None, "--non-printable", "write non-printable characters " + "into the output file", "non_printable", True, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print cracker.get_version() + sys.exit(0) + + args = p.parse_args() + try: + cracker.brute_force(args.string, args.output_file, args.method, + args.int_ordinals, args.non_printable, + args.no_limit) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python2/rotate-rot128.py b/python2/rotate-rot128.py new file mode 100755 index 0000000..69c7235 --- /dev/null +++ b/python2/rotate-rot128.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT128 encryption/decryption script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import rot128 + + try: + p = clap.Parser() + except Exception as e: + print "%s: error: %s" % (os.path.basename(sys.argv[0]), e) + sys.exit(1) + + p.set_description("Encrypt or decrypt a file using ROT128 with the " + "default rotation value or a user-defined one (using " + "the ROT128 character set).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_predef("-a", "--action", "action to perform", "action", + ["encrypt", "decrypt"], True) + p.add_avalue("-i", "--input-file", "input file path", "input_file", None, + True) + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + + # Define optional arguments + p.add_avalue("-b", "--buffer-size", "buffer size in bytes", "buffer_size", + 4096, False) + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_avalue("-v", "--value", "user-defined rotation value between 0 and " + "255", "value", 128, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print rot128.get_version() + sys.exit(0) + + args = p.parse_args() + if args.action is None: + p.error("The required action argument is missing.") + elif args.action.lower() == ("encrypt"): + encrypt = True + elif args.action.lower() == ("decrypt"): + encrypt = False + else: + p.error("An unsupported action was given.") + + try: + if encrypt: + rot128.encrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + else: + rot128.decrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python2/rotate-rot13.py b/python2/rotate-rot13.py new file mode 100755 index 0000000..16af6d6 --- /dev/null +++ b/python2/rotate-rot13.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT13 encryption/decryption script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import rot13 + + try: + p = clap.Parser() + except Exception as e: + print "%s: error: %s" % (os.path.basename(sys.argv[0]), e) + sys.exit(1) + + p.set_description("Encrypt or decrypt a file using ROT13 with the " + "default rotation value or a user-defined one (using " + "the ROT13 character set).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_predef("-a", "--action", "action to perform", "action", + ["encrypt", "decrypt"], True) + p.add_avalue("-i", "--input-file", "input file path", "input_file", None, + True) + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + + # Define optional arguments + p.add_avalue("-b", "--buffer-size", "buffer size in bytes", "buffer_size", + 4096, False) + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_avalue("-v", "--value", "user-defined rotation value between 0 and " + "25", "value", 13, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print rot13.get_version() + sys.exit(0) + + args = p.parse_args() + if args.action is None: + p.error("The required action argument is missing.") + elif args.action.lower() == ("encrypt"): + encrypt = True + elif args.action.lower() == ("decrypt"): + encrypt = False + else: + p.error("An unsupported action was given.") + + try: + if encrypt: + rot13.encrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + else: + rot13.decrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python2/rotate-rot47.py b/python2/rotate-rot47.py new file mode 100755 index 0000000..b5e3e4d --- /dev/null +++ b/python2/rotate-rot47.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT47 encryption/decryption script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import rot47 + + try: + p = clap.Parser() + except Exception as e: + print "%s: error: %s" % (os.path.basename(sys.argv[0]), e) + sys.exit(1) + + p.set_description("Encrypt or decrypt a file using ROT47 with the " + "default rotation value or a user-defined one (using " + "the ROT47 character set).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_predef("-a", "--action", "action to perform", "action", + ["encrypt", "decrypt"], True) + p.add_avalue("-i", "--input-file", "input file path", "input_file", None, + True) + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + + # Define optional arguments + p.add_avalue("-b", "--buffer-size", "buffer size in bytes", "buffer_size", + 4096, False) + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_avalue("-v", "--value", "user-defined rotation value between 0 and " + "93", "value", 47, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print rot47.get_version() + sys.exit(0) + + args = p.parse_args() + if args.action is None: + p.error("The required action argument is missing.") + elif args.action.lower() == ("encrypt"): + encrypt = True + elif args.action.lower() == ("decrypt"): + encrypt = False + else: + p.error("An unsupported action was given.") + + try: + if encrypt: + rot47.encrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + else: + rot47.decrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python3/changelog.txt b/python3/changelog.txt new file mode 100644 index 0000000..c5739f6 --- /dev/null +++ b/python3/changelog.txt @@ -0,0 +1,57 @@ + +CHANGELOG (ROTate) + + Version 3.0.6 (2018-03-13) + + + Added new versions of the Clap and PaVal core modules (replaced the + existing ones). + + * Revised (refurbished) all components of the project in general + (neglibible changes). + + # Fixed the wildcard bug (certain characters inside the strings to + encrypt and decrypt and will no longer be interpreted as wildcards). + + Version 3.0.5 (2015-01-03) + + * Revised some code inside the ROTate Cracker core module (negligible + changes). + + - Removed unnecessary module imports from the core modules. + + Version 3.0.4 (2014-04-03) + + + Added an optional command-line argument to the ROTate Cracker script + to write the integer ordinals of the decrypted string into the + output file. + + Version 3.0.3 (2014-03-21) + + * Revised (reduced) some code inside the ROTate Cracker core module. + * Revised the ROTate Cracker output file (non-printable characters are + now replaced either with whitespaces or a corresponding notice). + + # Fixed the attribute error inside the ROTate Cracker core module when + reading out the major version of the Python framework using Python + version 2.6 or below. + + Version 3.0.2 (2014-03-14) + + + Added an error handler to the ROTate scripts in case no command-line + argument parser can be initialized. + + * Revised (reduced) some code inside the ROTate Cracker core module. + * Revised the transform methods inside the ROT13, ROT47 and ROT128 + core module (reduced some code for increased readability). + + Version 3.0.1 (2014-03-07) + + * Revised the description of some command-line arguments inside all + ROTate scripts. + * Revised the header of the ROTate Cracker output file (negligible + text changes). + + Version 3.0.0 (2014-02-11) + + * First official release of this major version. + diff --git a/python3/core/__init__.py b/python3/core/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/python3/core/clap.py b/python3/core/clap.py new file mode 100755 index 0000000..e502975 --- /dev/null +++ b/python3/core/clap.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# Clap - Command-line argument parser module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/clap +# ============================================================================ + +__version__ = "1.1.10" + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +class Parser(object): + """ + Project independent command-line argument parser class. + """ + __arg_grp_opt = None + __arg_grp_req = None + __arg_parser = None + __is_argparser = False + __conflict_handler = "resolve" # used by OptionParser, only + + def __init__(self): + try: + from argparse import ArgumentParser + self.__arg_parser = ArgumentParser(add_help=False) + self.__arg_grp_req = \ + self.__arg_parser.add_argument_group("required arguments") + self.__arg_grp_opt = \ + self.__arg_parser.add_argument_group("optional arguments") + self.__is_argparser = True + return + except ImportError: + # Ignore the exception and proceed with the fallback + pass + + try: + from optparse import OptionParser + self.__arg_parser = \ + OptionParser(conflict_handler=self.__conflict_handler) + self.__arg_grp_req = \ + self.__arg_parser.add_option_group("Required arguments") + self.__arg_grp_opt = \ + self.__arg_parser.add_option_group("Optional arguments") + return + except ImportError: + # This should never happen + raise ImportError("Failed to initialize an argument parser.") + + def add_avalue(self, arg_short, arg_long, arg_help, arg_dest, arg_default, + arg_required): + """ + Add an argument that expects a single user-defined value. + """ + if arg_required: + obj = self.__arg_grp_req + else: + obj = self.__arg_grp_opt + + if arg_default is not None: + # Enclose the value with quotes in case it is not an integer + quotes = "'" + try: + arg_default = int(arg_default) + quotes = "" + except ValueError: + pass + + if arg_help.strip().endswith(")"): + arg_help = arg_help.rstrip(")") + arg_help += ", default is %s%s%s)" % \ + (quotes, str(arg_default), quotes) + else: + arg_help += " (default is %s%s%s)" % \ + (quotes, str(arg_default), quotes) + + if self.__is_argparser: + if arg_short is None: + obj.add_argument(arg_long, help=arg_help, dest=arg_dest, + default=arg_default, required=arg_required) + else: + obj.add_argument(arg_short, arg_long, help=arg_help, + dest=arg_dest, default=arg_default, + required=arg_required) + else: + if arg_short is None: + obj.add_option(arg_long, help=arg_help, dest=arg_dest, + default=arg_default) + else: + obj.add_option(arg_short, arg_long, help=arg_help, + dest=arg_dest, default=arg_default) + + def add_predef(self, arg_short, arg_long, arg_help, arg_dest, arg_choices, + arg_required): + """ + Add an argument that expects a certain predefined value. + """ + if arg_required: + obj = self.__arg_grp_req + else: + obj = self.__arg_grp_opt + + if self.__is_argparser: + if arg_short is None: + obj.add_argument(arg_long, help=arg_help, dest=arg_dest, + choices=arg_choices, required=arg_required) + else: + obj.add_argument(arg_short, arg_long, help=arg_help, + dest=arg_dest, choices=arg_choices, + required=arg_required) + else: + if arg_short is None: + obj.add_option(arg_long, help=arg_help, dest=arg_dest, + choices=arg_choices) + else: + # The OptionParser does not print the values to choose from, + # so these have to be added manually to the description of + # the argument first + arg_help += " (choose from " + for item in arg_choices: + arg_help += "'%s', " % item + arg_help = arg_help.rstrip(", ") + ")" + + obj.add_option(arg_short, arg_long, help=arg_help, + dest=arg_dest) + + def add_switch(self, arg_short, arg_long, arg_help, arg_dest, arg_store, + arg_required): + """ + Add an argument that does not expect anything, but returns a + boolean value. + """ + if arg_required: + obj = self.__arg_grp_req + else: + obj = self.__arg_grp_opt + + if arg_store: + arg_store = "store_true" + else: + arg_store = "store_false" + + if self.__is_argparser: + if arg_short is None: + obj.add_argument(arg_long, help=arg_help, dest=arg_dest, + action=arg_store, required=arg_required) + else: + obj.add_argument(arg_short, arg_long, help=arg_help, + dest=arg_dest, action=arg_store, + required=arg_required) + else: + if arg_short is None: + obj.add_option(arg_long, help=arg_help, dest=arg_dest, + action=arg_store) + else: + obj.add_option(arg_short, arg_long, help=arg_help, + dest=arg_dest, action=arg_store) + + def dependency(self, arg_name, arg_value, dependency): + """ + Check the dependency of a command-line argument. + """ + if dependency is not None: + if arg_value is None or str(arg_value) == "": + raise Exception("The '%s' argument depends on %s'." % + (arg_name, dependency)) + + def error(self, obj): + """ + Raise an error and cause the argument parser to print the error + message. + """ + if type(obj) == str: + obj = obj.strip() + + self.__arg_parser.error(obj) + + def parse_args(self): + """ + Parse and return the command-line arguments. + """ + if self.__is_argparser: + args = self.__arg_parser.parse_args() + else: + (args, values) = self.__arg_parser.parse_args() + return args + + def print_help(self): + """ + Print the usage, description, argument details and epilog. + """ + self.__arg_parser.print_help() + + def set_description(self, string): + """ + Set the description text. + """ + self.__arg_parser.description = string.strip() + + def set_epilog(self, string): + """ + Set the epilog text. + """ + self.__arg_parser.epilog = string.strip() + +# EOF diff --git a/python3/core/common.py b/python3/core/common.py new file mode 100755 index 0000000..3a5194d --- /dev/null +++ b/python3/core/common.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# Common core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +from . import paval as pv + + +def get_file_size(file_path): + """ + Get the size of a file in bytes. + """ + pv.path(file_path, "", True, True) + + f = open(file_path, "rb") + f.seek(0, 2) + file_size = f.tell() + f.close() + + return int(file_size) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + +# EOF diff --git a/python3/core/cracker.py b/python3/core/cracker.py new file mode 100755 index 0000000..aa7f37b --- /dev/null +++ b/python3/core/cracker.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# Cracker core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +import os +from . import paval as pv +from . import rot13 +from . import rot47 +from . import rot128 +import string as st +import sys + +from datetime import datetime as dt + + +def brute_force(string, file_output, method=None, int_ordinals=False, + non_printable=False, limit=True): + """ + Brute-force the given string to find out which ROT variant and + rotation value was used to encrypt. + """ + pv.path(file_output, "output", True, False) + pv.string(string, "string to decrypt", True) + file_output = os.path.abspath(file_output) + + if method is None: + method = "All" + else: + method = method.upper() + pv.compstr(method, "method", ["ROT13", "ROT47", "ROT128"]) + + list_values_rot13 = [] + list_values_rot47 = [] + list_values_rot128 = [] + timestamp = str(dt.now()) + output = "\r\n" + "=" * 78 + \ + "\r\nFile type: ROTate Cracker output file" \ + "\r\n" + "-" * 78 + \ + "\r\nOutput file name: " + file_output + \ + "\r\nString to decrypt: " + string + \ + "\r\nMethods used: " + method + \ + "\r\n" + "-" * 78 + \ + "\r\nTimestamp: " + timestamp[:-7] + \ + "\r\nROTate version: " + get_version() + \ + "\r\n" + "=" * 78 + "\r\n\r\n" + + if method == "All" or method == "ROT13": + list_values_rot13 = \ + __get_values_rot13(string, int_ordinals, non_printable, limit) + if method == "All" or method == "ROT47": + list_values_rot47 = \ + __get_values_rot47(string, int_ordinals, non_printable, limit) + if method == "All" or method == "ROT128": + list_values_rot128 = \ + __get_values_rot128(string, int_ordinals, non_printable, limit) + + if len(list_values_rot13) > 0: + output += "\r\n [ROT13]\r\n" + for value in list_values_rot13: + output += " - %s\r\n" % value + output += "\r\n" + if len(list_values_rot47) > 0: + output += "\r\n [ROT47]\r\n" + for value in list_values_rot47: + output += " - %s\r\n" % value + output += "\r\n" + if len(list_values_rot128) > 0: + output += "\r\n [ROT128]\r\n" + for value in list_values_rot128: + output += " - %s\r\n" % value + output += "\r\n" + fh_output = open(file_output, "wb") + + # Run the appropriate code for the Python framework used + if sys.version_info[0] == 2: + fh_output.write(output) + elif sys.version_info[0] > 2: + fh_output.write(output.encode(sys.getdefaultencoding())) + + fh_output.close() + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __get_int_ordinals(string): + """ + Return the integer ordinals of a string. + """ + output = "" + + for char in string: + output += str(ord(char)).rjust(3, " ") + ", " + output = output.rstrip(", ") + + return output + + +def __get_printable(string): + """ + Replace non-printable characters inside a string with whitespaces + """ + output = "" + + chars_remove = "\t\n\r\x0b\x0c" + for char in chars_remove: + string = string.replace(char, " ") + + for char in string: + if char not in st.printable: + output += " " + else: + output += char + + if output.strip() == "": + output = "(only non-printable characters or spaces)" + + return output + + +def __get_values_rot13(string, int_ordinals, non_printable, limit): + """ + Core method to get all possible ROT13 values for the given string. + """ + list_values = [] + for i in range(1, 26): + output = __prepare_line(rot13.decrypt_string(string, i), + int_ordinals, non_printable, limit) + list_values.append("Value %s: %s" % (str(i).rjust(3, " "), output)) + + return list_values + + +def __get_values_rot47(string, int_ordinals, non_printable, limit): + """ + Core method to get all possible ROT47 values for the given string. + """ + list_values = [] + for i in range(1, 94): + output = __prepare_line(rot47.decrypt_string(string, i), + int_ordinals, non_printable, limit) + list_values.append("Value %s: %s" % (str(i).rjust(3, " "), output)) + + return list_values + + +def __get_values_rot128(string, int_ordinals, non_printable, limit): + """ + Core method to get all possible ROT128 values for the given string. + """ + list_values = [] + for i in range(1, 256): + output = __prepare_line(rot128.decrypt_string(string, i), + int_ordinals, non_printable, limit) + list_values.append("Value %s: %s" % (str(i).rjust(3, " "), output)) + + return list_values + + +def __prepare_line(line, int_ordinals, non_printable, limit): + """ + Prepare the line before it gets written into the file. + """ + if int_ordinals: + line = __get_int_ordinals(line) + else: + if not non_printable: + line = __get_printable(line) + + if limit: + if len(line) > 58: + line = line[:55] + "..." + + return line + +# EOF diff --git a/python3/core/paval.py b/python3/core/paval.py new file mode 100755 index 0000000..159f357 --- /dev/null +++ b/python3/core/paval.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# PaVal - Parameter validation module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/paval +# ============================================================================ + +__version__ = "1.2.7" + +import filecmp +import os + + +def compfile(path, name="", list_files=[]): + """ + Compare files to avoid that the same file is given multiple times or + in different ways (e. g. different name but same content). + """ + __string(path, "%s path" % name, True) + + if list_files is None: + list_files = [] + elif len(list_files) == 0: + __ex("File list is empty (no files to compare with).", True) + else: + for item in list_files: + if not type(item) == list: + __ex("Every list item must be a sub-list.", True) + if not len(item) == 2: + __ex("Every sub-list must contain two items.", True) + + path = os.path.abspath(path) + for item in list_files: + path_compare = os.path.abspath(str(item[0])) + name_compare = str(item[1]) + if path == path_compare: + __ex("The %s and the %s file path must not be identical." % + (name, name_compare), False) + if os.path.exists(path) and os.path.exists(path_compare): + if filecmp.cmp(path, path_compare, 0): + __ex("The %s and %s file content must not be identical." % + (name, name_compare), False) + + +def compstr(string, name="", list_strings=[]): + """ + Compare a string with a list of strings and check if it is an item of + that list. + """ + __string(string, name, False) + if len(list_strings) == 0: + __ex("No %s strings to compare with." % name, True) + if string not in list_strings: + __ex("The %s '%s' does not exist." % (name, string), False) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def intrange(value, name="", value_min=None, value_max=None, zero=False): + """ + Validate an integer range. + """ + value = __integer(value, "%s value" % name, False) + if value_min is not None: + value_min = __integer(value_min, "minimal %s value" % name, True) + intvalue(value_min, name, True, True, True) + if value_max is not None: + value_max = __integer(value_max, "maximal %s value" % name, True) + intvalue(value_max, name, True, True, True) + if not zero: + if value == 0: + __ex("The %s value must not be zero." % name, False) + if (value_min is not None) and (value_max is not None): + if value_min > value_max: + __ex("The maximal %s value must be greater than the minimal " + "value." % name, False) + if (value_min == value_max) and (not value == value_min): + __ex("The %s value can only be %s (depending on further range " + "further range arguments)." % (name, value_min), False) + if (value < value_min) or (value > value_max): + __ex("The %s value must be between %s and %s (depending on " + "further range arguments)." % (name, value_min, value_max), + False) + elif value_min is not None: + if value < value_min: + __ex("The %s value must not be less than %s." % (name, value_min), + False) + elif value_max is not None: + if value > value_max: + __ex("The %s value must not be greater than %s." % + (name, value_max), False) + + +def intvalue(value, name="", positive=True, zero=False, negative=False): + """ + Validate a single integer value. + """ + value = __integer(value, "%s value" % name, False) + if not positive: + if value > 0: + __ex("The %s value must not be positive." % name, False) + if not zero: + if value == 0: + __ex("The %s value must not be zero." % name, False) + if not negative: + if value < 0: + __ex("The %s value must not be negative." % name, False) + + +def path(path, name="", is_file=False, exists=False): + """ + Validate a path of a file or directory. + """ + string(path, "%s path" % name, False, None) + path = os.path.abspath(path) + + if is_file: + path_type = "file" + else: + path_type = "directory" + if exists: + if not os.path.exists(path): + __ex("The given %s %s does not exist." % (name, path_type), False) + if (is_file and not os.path.isfile(path)) or \ + (not is_file and not os.path.isdir(path)): + __ex("The given %s %s path is not a %s." % (name, path_type, + path_type), False) + else: + if os.path.exists(path): + __ex("The given %s %s path already exists." % (name, path_type), + False) + + +def string(string, name="", wildcards=False, invalid_chars=None): + """ + Validate a string. + """ + __string(string, name, False) + if invalid_chars is None: + invalid_chars = "" + if not wildcards: + if ("*" in string) or ("?" in string): + __ex("The %s must not contain wildcards." % name, False) + if len(invalid_chars) > 0: + for char in invalid_chars: + if char in string: + # Use single quotes by default or double quotes in case the + # single quotes are the invalid character + quotes = "'" + if char == quotes: + quotes = "\"" + + __ex("The %s contains at least one invalid character " + "(%s%s%s)." % (name, quotes, char, quotes), False) + + +def __ex(string, internal=False): + """ + Internal method to raise an exception. + """ + string = str(string).strip() + while (" " * 2) in string: + string = string.replace((" " * 2), " ") + if internal: + string = "PaVal: " + string + raise Exception(string) + + +def __integer(value, name="", internal=False): + """ + Internal method for basic integer validation. + """ + if value is None: + __ex("The %s is missing." % name, internal) + if value == "": + __ex("The %s must not be empty." % name, internal) + try: + value = int(value) + except ValueError: + __ex("The %s must be an integer." % name, internal) + return int(value) + + +def __string(string, name="", internal=False): + """ + Internal method for basic string validation. + """ + if string is None: + __ex("The %s is missing." % name, internal) + if string == "": + __ex("The %s must not be empty." % name, internal) + +# EOF diff --git a/python3/core/rot128.py b/python3/core/rot128.py new file mode 100755 index 0000000..e295a54 --- /dev/null +++ b/python3/core/rot128.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT128 encryption/decryption core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +from . import common +import os +from . import paval as pv + + +def encrypt_file(file_input, file_output, buffer_size=4096, rot_value=128): + """ + Encrypt a file using ROT128. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def encrypt_string(string, rot_value): + """ + Encrypt a string using ROT128. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(True, string, rot_value) + + +def decrypt_file(file_input, file_output, buffer_size=4096, rot_value=128): + """ + Decrypt a file using ROT128. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def decrypt_string(string, rot_value): + """ + Decrypt a string using ROT128. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(False, string, rot_value) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __transform_bytes(encrypt, data_input, rot_value): + """ + Core method to manipulate bytes. + """ + data_output = bytearray(b"") + + for byte in data_input: + if encrypt: + data_output.append(((byte + rot_value) % 256)) + else: + data_output.append(((byte - rot_value) % 256)) + + return data_output + + +def __transform_string(encrypt, string, rot_value): + """ + Core method to manipulate a string. + """ + output = "" + + for char in string: + if encrypt: + output += chr(((ord(char) + rot_value) % 256)) + else: + output += chr(((ord(char) + rot_value) % 256)) + + return output + +# EOF diff --git a/python3/core/rot13.py b/python3/core/rot13.py new file mode 100755 index 0000000..03833b7 --- /dev/null +++ b/python3/core/rot13.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT13 encryption/decryption core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +from . import common +import os +from . import paval as pv + + +def encrypt_file(file_input, file_output, buffer_size=4096, rot_value=13): + """ + Encrypt a file using ROT13. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(True, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def encrypt_string(string, rot_value=13): + """ + Encrypt a string using ROT13. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(True, string, rot_value) + + +def decrypt_file(file_input, file_output, buffer_size=4096, rot_value=13): + """ + Decrypt a file using ROT13. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def decrypt_string(string, rot_value=13): + """ + Decrypt a string using ROT13. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(False, string, rot_value) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __transform_bytes(encrypt, data_input, rot_value): + """ + Core method to manipulate bytes. + """ + data_output = bytearray(b"") + + for byte in data_input: + if byte in range(65, 91): + # Uppercase letters + if encrypt: + data_output.append((((byte - 65) + rot_value) % 26) + 65) + else: + data_output.append((((byte - 65) - rot_value) % 26) + 65) + elif byte in range(97, 123): + # Lowercase letters + if encrypt: + data_output.append((((byte - 97) + rot_value) % 26) + 97) + else: + data_output.append((((byte - 97) - rot_value) % 26) + 97) + else: + data_output.append(byte) + + return data_output + + +def __transform_string(encrypt, string, rot_value): + """ + Core method to manipulate a string. + """ + output = "" + + for char in string: + if ord(char) in range(65, 91): + # Uppercase letters + if encrypt: + output += chr((((ord(char) - 65) + rot_value) % 26) + 65) + else: + output += chr((((ord(char) - 65) - rot_value) % 26) + 65) + elif ord(char) in range(97, 123): + # Lowercase letters + if encrypt: + output += chr((((ord(char) - 97) + rot_value) % 26) + 97) + else: + output += chr((((ord(char) - 97) - rot_value) % 26) + 97) + else: + output += char + + return output + +# EOF diff --git a/python3/core/rot47.py b/python3/core/rot47.py new file mode 100755 index 0000000..6ef3c47 --- /dev/null +++ b/python3/core/rot47.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT47 encryption/decryption core module +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +__version__ = "3.0.6" + +from . import common +import os +from . import paval as pv + + +def encrypt_file(file_input, file_output, buffer_size=4096, rot_value=47): + """ + Encrypt a file using ROT47. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def encrypt_string(string, rot_value=47): + """ + Encrypt a string using ROT47. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(True, string, rot_value) + + +def decrypt_file(file_input, file_output, buffer_size=4096, rot_value=47): + """ + Decrypt a file using ROT47. + """ + pv.path(file_input, "input", True, True) + pv.path(file_output, "output", True, False) + pv.intvalue(buffer_size, "buffer size", True, False, False) + pv.intvalue(rot_value, "ROT", True, False, False) + pv.compfile(file_input, "input", [[file_output, "output"]]) + + buffer_size = int(buffer_size) + rot_value = int(rot_value) + file_input = os.path.abspath(file_input) + file_output = os.path.abspath(file_output) + + fh_input = open(file_input, "rb") + fh_output = open(file_output, "wb") + + file_size = common.get_file_size(file_input) + byte_blocks = int(file_size / buffer_size) + byte_remainder = file_size % buffer_size + + for block in range(byte_blocks): + data_input = bytearray(b"" + fh_input.read(buffer_size)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + if byte_remainder > 0: + data_input = bytearray(b"" + fh_input.read(byte_remainder)) + fh_output.write(__transform_bytes(False, data_input, rot_value)) + + fh_input.close() + fh_output.close() + + +def decrypt_string(string, rot_value=47): + """ + Decrypt a string using ROT47. + """ + pv.string(string, "string", True) + pv.intvalue(rot_value, "ROT", True, False, False) + + return __transform_string(False, string, rot_value) + + +def get_version(): + """ + Return the version of this module. + """ + return __version__ + + +def __transform_bytes(encrypt, data_input, rot_value): + """ + Core method to manipulate bytes. + """ + data_output = bytearray(b"") + + for byte in data_input: + if byte in range(32, 126): + if encrypt: + data_output.append((((byte - 32) + rot_value) % 94) + 32) + else: + data_output.append((((byte - 32) - rot_value) % 94) + 32) + else: + data_output.append(byte) + + return data_output + + +def __transform_string(encrypt, string, rot_value): + """ + Core method to manipulate a string. + """ + output = "" + + for char in string: + if ord(char) in range(32, 126): + if encrypt: + output += chr((((ord(char) - 32) + rot_value) % 94) + 32) + else: + output += chr((((ord(char) - 32) - rot_value) % 94) + 32) + else: + output += char + + return output + +# EOF diff --git a/python3/docs/usage_rotate-cracker.txt b/python3/docs/usage_rotate-cracker.txt new file mode 100644 index 0000000..60c548f --- /dev/null +++ b/python3/docs/usage_rotate-cracker.txt @@ -0,0 +1,83 @@ + +USAGE (rotate-cracker.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Crack a ROT encrypted file + + 1. Definition + + The ROTate Cracker script helps to determine which ROT variant and + rotation value was used to encrypt a file or string by trying all + supported ROT variants with all rotation values available (brute + force). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-cracker.py --help + + 3. Crack a ROT encrypted file + + For example, you have the ROT encrypted file "secret.txt" containing + the line + + Uryyb, Jbeyq! + + and want to decrypt it. So, to find out which ROT method and rotation + value was used to encrypt the file, a string from the file (e. g. a + word) is required. + + This example uses the string "Uryyb" and writes the decrypted values + into the file "/tmp/output.txt": + + $ ./rotate-cracker.py -s "Uryyb" -o /tmp/output.txt + + The output file shows that when using the ROT13 method, the string + "Uryyb" decrypted with value 13 returns the word "Hello": + + (...) + [ROT13] + - Value 0: Uryyb + - Value 1: Tqxxa + - Value 2: Spwwz + - Value 3: Rovvy + - Value 4: Qnuux + - Value 5: Pmttw + - Value 6: Olssv + - Value 7: Nkrru + - Value 8: Mjqqt + - Value 9: Lipps + - Value 10: Khoor + - Value 11: Jgnnq + - Value 12: Ifmmp + - Value 13: Hello + (...) + + So, the file or at least that string seems to be encrypted with that + method and value. Unfortunately, there is no analysis feature, which + means you will have to look at the returned value list to manually + check which entry makes most sense. + + If there are non-printable characters inside the string, they will be + replaced by whitespaces. If the string only contains of whitespaces, + a notice will be written to the output file. + diff --git a/python3/docs/usage_rotate-rot128.txt b/python3/docs/usage_rotate-rot128.txt new file mode 100644 index 0000000..53b835d --- /dev/null +++ b/python3/docs/usage_rotate-rot128.txt @@ -0,0 +1,56 @@ + +USAGE (rotate-rot128.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Encrypt a file + 4. Decrypt the file again + 5. User-defined rotation values + + 1. Definition + + The ROTate ROT128 script encrypts and decrypts a file using the ROT128 + method with the default rotation value or a user-defined one (using + the ROT128 character set). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-rot128.py --help + + 3. Encrypt a file + + This works as described in section 3 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT128 instead of the + script used there. + + 4. Decrypt the file again + + This works as described in section 4 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT128 instead of the + script used there. + + 5. User-defined rotation values + + This works as described in section 5 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT128 instead of the + script used there. + diff --git a/python3/docs/usage_rotate-rot13.txt b/python3/docs/usage_rotate-rot13.txt new file mode 100644 index 0000000..918322b --- /dev/null +++ b/python3/docs/usage_rotate-rot13.txt @@ -0,0 +1,74 @@ + +USAGE (rotate-rot13.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Encrypt a file + 4. Decrypt the file again + 5. User-defined rotation values + + 1. Definition + + The ROTate ROT13 script encrypts and decrypts a file using the ROT13 + method with the default rotation value or a user-defined one (using + the ROT13 character set). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-rot13.py --help + + 3. Encrypt a file + + For example, if you have the input file "hello.txt" containing the + line + + Hello, world! + + and want to encrypt it using ROT13 (with its default value) and write + the encrypted data into "secret.txt", the command line would look like + this: + + $ ./rotate-rot13.py -i hello.txt -o secret.txt -a encrypt + + The encrypted data inside "secret.txt" should look like this: + + Uryyb, Jbeyq! + + 4. Decrypt the file again + + To decrypt the file again and write the decrypted data into the file + "output.txt", type: + + $ ./rotate-rot13.py -i secret.txt -o output.txt -a decrypt + + 5. User-defined rotation values + + You can also encrypt the file using the ROT13 method, but with + rotation value 19 instead of the default value: + + $ ./rotate-rot13.py -i hello.txt -o secret.txt -a encrypt -v 19 + + The user-defined rotation value used to encrypt is also required to + properly decrypt the file again: + + $ ./rotate-rot13.py -i secret.txt -o output.txt -a decrypt -v 19 + diff --git a/python3/docs/usage_rotate-rot47.txt b/python3/docs/usage_rotate-rot47.txt new file mode 100644 index 0000000..1498be1 --- /dev/null +++ b/python3/docs/usage_rotate-rot47.txt @@ -0,0 +1,56 @@ + +USAGE (rotate-rot47.py) + + Contents: + + 1. Definition + 2. General stuff + 2.1 How to run Python scripts + 2.2 Overview of all command-line arguments + 3. Encrypt a file + 4. Decrypt the file again + 5. User-defined rotation values + + 1. Definition + + The ROTate ROT47 script encrypts and decrypts a file using the ROT47 + method with the default rotation value or a user-defined one (using + the ROT47 character set). + + 2. General stuff + + 2.1 How to run Python scripts + + All usage examples below show how to execute the Python scripts on + the shell of a Unix-like system. If you do not know, how to run + those scripts on your operating system, you may have a look at + this page: + + http://www.urbanware.org/howto_python.html + + 2.2 Overview of all command-line arguments + + Usually, each script requires command-line arguments to operate. + So, to get an overview of all arguments available, simply run the + script with the "--help" argument. For example: + + $ ./rotate-rot47.py --help + + 3. Encrypt a file + + This works as described in section 3 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT47 instead of the script + used there. + + 4. Decrypt the file again + + This works as described in section 4 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT47 instead of the script + used there. + + 5. User-defined rotation values + + This works as described in section 5 inside the ROT13 documentation, + but, of course, you need to run the ROTate ROT47 instead of the script + used there. + diff --git a/python3/license.txt b/python3/license.txt new file mode 100644 index 0000000..d87dbbb --- /dev/null +++ b/python3/license.txt @@ -0,0 +1,33 @@ + +LICENSE (ROTate) + + General + + This project is distributed under the MIT License which can be found + below, inside the file "readme.txt" as well as in the header of each + script file. In case the license text is missing for some reason, you + can also find it here: + + http://www.urbanware.org/license.html + + License terms + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/python3/readme.txt b/python3/readme.txt new file mode 100644 index 0000000..34bb176 --- /dev/null +++ b/python3/readme.txt @@ -0,0 +1,49 @@ + +README (ROTate) + + Project + + ROTate + Version 3.0.6 (based on Python framework 3.x) + Copyright (C) 2018 by Ralf Kilian + + Website: http://www.urbanware.org + GitHub: https://github.com/urbanware-org/rotate + + Definition + + The ROTate project is a collection of scripts to encrypt and decrypt + files using various ROT cipher methods. + + License + + This project is distributed under the MIT License. You should have + received a copy of the license along with this program (see the + 'license.txt' file). If not, you can find the license terms here: + + https://opensource.org/licenses/MIT + + Requirements + + The requirements for this project can be found inside the included + file 'requirements.txt'. + + In case this file is missing, you can also find the information on the + website of the project mentioned above. + + Usage + + For fundamental documentation as well as some usage examples for each + component of the project, you may have a look at the text files inside + the included 'docs' sub-directory. + + Legal information + + The project name is completely fictitious. Any correspondences with + existing websites, applications, companies and/or other projects are + purely coincidental. + + All trademarks belong to their respective owners. + + Errors and omissions excepted. + diff --git a/python3/requirements.txt b/python3/requirements.txt new file mode 100644 index 0000000..5392db1 --- /dev/null +++ b/python3/requirements.txt @@ -0,0 +1,17 @@ + +REQUIREMENTS (ROTate) + + Notice + + This version of ROTate was built for the Python 3.x framework. If you + need a version that works with Python 2.x, you may look here: + + http://github.com/urbanware-org/rotate + + General + + Software requirements: + + - Python 2.x (version 2.7 or higher is recommended, may also work + with earlier versions) + diff --git a/python3/rotate-cracker.py b/python3/rotate-cracker.py new file mode 100755 index 0000000..e63915e --- /dev/null +++ b/python3/rotate-cracker.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# Cracker script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import cracker + + try: + p = clap.Parser() + except Exception as e: + print("%s: error: %s" % (os.path.basename(sys.argv[0]), e)) + sys.exit(1) + + p.set_description("Determine which ROT variant and rotation value was " + "used to encrypt a file or string by trying all " + "supported ROT variants with all rotation values " + "available (brute force).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + p.add_avalue("-s", "--string", "string to decrypt", "string", None, True) + + # Define optional arguments + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_switch(None, "--int-ordinals", "write integer ordinals instead " + "of the characters into the output file", "int_ordinals", + True, False) + p.add_predef("-m", "--method", "use only one instead of all supported " + "methods to decrypt", "method", ["rot13", "rot47", "rot128"], + False) + p.add_switch(None, "--no-limit", "do not limit the length of the lines " + "inside the output file", "no_limit", False, False) + p.add_switch(None, "--non-printable", "write non-printable characters " + "into the output file", "non_printable", True, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print(cracker.get_version()) + sys.exit(0) + + args = p.parse_args() + try: + cracker.brute_force(args.string, args.output_file, args.method, + args.int_ordinals, args.non_printable, + args.no_limit) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python3/rotate-rot128.py b/python3/rotate-rot128.py new file mode 100755 index 0000000..fddfbc2 --- /dev/null +++ b/python3/rotate-rot128.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT128 encryption/decryption script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import rot128 + + try: + p = clap.Parser() + except Exception as e: + print("%s: error: %s" % (os.path.basename(sys.argv[0]), e)) + sys.exit(1) + + p.set_description("Encrypt or decrypt a file using ROT128 with the " + "default rotation value or a user-defined one (using " + "the ROT128 character set).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_predef("-a", "--action", "action to perform", "action", + ["encrypt", "decrypt"], True) + p.add_avalue("-i", "--input-file", "input file path", "input_file", None, + True) + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + + # Define optional arguments + p.add_avalue("-b", "--buffer-size", "buffer size in bytes", "buffer_size", + 4096, False) + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_avalue("-v", "--value", "user-defined rotation value between 0 and " + "255", "value", 128, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print(rot128.get_version()) + sys.exit(0) + + args = p.parse_args() + if args.action is None: + p.error("The required action argument is missing.") + elif args.action.lower() == ("encrypt"): + encrypt = True + elif args.action.lower() == ("decrypt"): + encrypt = False + else: + p.error("An unsupported action was given.") + + try: + if encrypt: + rot128.encrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + else: + rot128.decrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python3/rotate-rot13.py b/python3/rotate-rot13.py new file mode 100755 index 0000000..c14dfd9 --- /dev/null +++ b/python3/rotate-rot13.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT13 encryption/decryption script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import rot13 + + try: + p = clap.Parser() + except Exception as e: + print("%s: error: %s" % (os.path.basename(sys.argv[0]), e)) + sys.exit(1) + + p.set_description("Encrypt or decrypt a file using ROT13 with the " + "default rotation value or a user-defined one (using " + "the ROT13 character set).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_predef("-a", "--action", "action to perform", "action", + ["encrypt", "decrypt"], True) + p.add_avalue("-i", "--input-file", "input file path", "input_file", None, + True) + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + + # Define optional arguments + p.add_avalue("-b", "--buffer-size", "buffer size in bytes", "buffer_size", + 4096, False) + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_avalue("-v", "--value", "user-defined rotation value between 0 and " + "25", "value", 13, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print(rot13.get_version()) + sys.exit(0) + + args = p.parse_args() + if args.action is None: + p.error("The required action argument is missing.") + elif args.action.lower() == ("encrypt"): + encrypt = True + elif args.action.lower() == ("decrypt"): + encrypt = False + else: + p.error("An unsupported action was given.") + + try: + if encrypt: + rot13.encrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + else: + rot13.decrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/python3/rotate-rot47.py b/python3/rotate-rot47.py new file mode 100755 index 0000000..78d6cd4 --- /dev/null +++ b/python3/rotate-rot47.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ============================================================================ +# ROTate - Encryption tool based on the ROT cipher +# ROT47 encryption/decryption script +# Copyright (C) 2018 by Ralf Kilian +# Distributed under the MIT License (https://opensource.org/licenses/MIT) +# +# Website: http://www.urbanware.org +# GitHub: https://github.com/urbanware-org/rotate +# ============================================================================ + +import os +import sys + + +def main(): + from core import clap + from core import rot47 + + try: + p = clap.Parser() + except Exception as e: + print("%s: error: %s" % (os.path.basename(sys.argv[0]), e)) + sys.exit(1) + + p.set_description("Encrypt or decrypt a file using ROT47 with the " + "default rotation value or a user-defined one (using " + "the ROT47 character set).") + p.set_epilog("Further information and usage examples can be found inside " + "the documentation file for this script.") + + # Define required arguments + p.add_predef("-a", "--action", "action to perform", "action", + ["encrypt", "decrypt"], True) + p.add_avalue("-i", "--input-file", "input file path", "input_file", None, + True) + p.add_avalue("-o", "--output-file", "output file path", "output_file", + None, True) + + # Define optional arguments + p.add_avalue("-b", "--buffer-size", "buffer size in bytes", "buffer_size", + 4096, False) + p.add_switch("-h", "--help", "print this help message and exit", None, + True, False) + p.add_avalue("-v", "--value", "user-defined rotation value between 0 and " + "93", "value", 47, False) + p.add_switch(None, "--version", "print the version number and exit", None, + True, False) + + if len(sys.argv) == 1: + p.error("At least one required argument is missing.") + elif ("-h" in sys.argv) or ("--help" in sys.argv): + p.print_help() + sys.exit(0) + elif "--version" in sys.argv: + print(rot47.get_version()) + sys.exit(0) + + args = p.parse_args() + if args.action is None: + p.error("The required action argument is missing.") + elif args.action.lower() == ("encrypt"): + encrypt = True + elif args.action.lower() == ("decrypt"): + encrypt = False + else: + p.error("An unsupported action was given.") + + try: + if encrypt: + rot47.encrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + else: + rot47.decrypt_file(args.input_file, args.output_file, + args.buffer_size, args.value) + except Exception as e: + p.error(e) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/rotate.png b/rotate.png new file mode 100644 index 0000000..2f7d554 Binary files /dev/null and b/rotate.png differ