Skip to content

X386 – Ubuntu & Python

Ubuntu and Python Documentation

  • Home
  • About
  • Contact
  • License
  • Privacy Policy

enc.py file encoder

Posted on 27/06/2020 - 29/09/2020 by exforge
#!/usr/bin/env python3
"""
enc -a -r [-v -q] -c chipper -d directory file1 file2 ..

Encode a file or group of files by given chipper. All arguments are
optional. If you omit the chipper, you'll be asked when the program 
begins. Encoding a file twice reverts it to the original status.

-c --chipper chipper encoding chipper value
-d --directory directory encode contents of the directory
-a --all encode hidden files too
-r --recursive traverse subdirectories too
-v --verbose verbose mode
-q --quiet quiet mode
file1 file2 .. encode given files

Return Codes:
0  : Everything is fine
11 : Empty file list, no files to encode

   ---Copyright (C) Exforge exforge@x386.xyz
   This document is free text: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   any later version.
   This document is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.


"""
import os
import argparse
import sys
import getpass

def decen(filename):
   """
   Decode a file with chippers

   filename: string of filename

   Return Codes:
   0 : OK
   11: File not exists or not a file
   12: Encode error
   """
   
   if not os.path.isfile(filename):
      return(11)     # file not exists or not a file, file error
   filelength = os.path.getsize(filename)
   lchippers = len(chippers)
   ckb = 1024              # 1 KB
   cmb = ckb * ckb         # 1 MB
   cgb = cmb * ckb         # 1 GB
   # Give percentage of completion at every MB
   breaker = cmb
   # Display file size
   if filelength > cgb:
      filesize = filelength // cgb 
      cfilesize = str(filesize) + " GB"
   elif filelength > cmb:
      filesize = filelength // cmb 
      cfilesize = str(filesize) + " MB"
   elif filelength > ckb:
      filesize = filelength // ckb 
      cfilesize = str(filesize) + " KB"
   else:
      cfilesize = str(filelength) + " B"
   # try opening and encoding file
   try:
      with open(filename, "r+b") as fio:
         if verbose:
            sys.stdout.write("Encoding " + filename + " " + cfilesize + "...........")
            sys.stdout.flush()
         indata = fio.read(filelength)
         outdata = bytearray(filelength)
         # XOR of bytes in file with the chipper bytes
         for i in range(filelength):
            chipper = chippers[i % lchippers]
            outdata[i] = indata[i] ^ chipper
            if verbose and (i>0) and (i % breaker == 0):
               percent = i / filelength
               b = ""
               if percent < 0.1:
                  b = " "
               sys.stdout.write(f"\b\b\b\b\b\b" + b+ "{:.2%}".format(percent))
               sys.stdout.flush()
         fio.seek(0)
         fio.write(outdata)
   except:
      return(12)
   if verbose:
      sys.stdout.write("\b\b\b\b\b\b done \n")
      sys.stdout.flush() 
   # Actually it means, (not verbose) and (not quiet)
   # In normal mode, display the name of the file encoded
   if not (verbose or quiet):
      sys.stdout.write(filename + "\n")
      sys.stdout.flush()
   return(0)

def traverse(path):
   """
   Traverse a given path, full files list with the filenames.
   If recursive flag is set, traverse subdirectories too.
   """
   cpath = path
   # if there is no / at the end of the directory, add it
   if path[-1] != "/":
      cpath = cpath + "/"
   # Get list of files in that dir
   files = os.listdir(cpath)
   files.sort()      # I love to sort
   # I really love to sort when it is that easy. I wrote so many sort routines
   #    in Pascal and C when I was a student. Now it is really easy. 
   for filename in files:
      # if the item is a directory, traverse it too (if recursive)
      if os.path.isdir(cpath + filename):
         if recursive:
            traverse(cpath + filename)
      # if the item is a file, depending if it is hidden or not, checking all flag
      elif os.path.isfile(cpath + filename):
         if (filename[0] == ".") and not all:
            continue
         allfiles.append(cpath + filename)
      

def getchipper():
   while True:
      print("Enter chipper (password), Ctrl-C to abort:")
      chipper1 = getpass.getpass()
      print("Enter chipper (password) again:")
      chipper2 = getpass.getpass()
      if chipper1 != chipper2:
         print("Passwords do not math, try again...")
         print()
         continue
      if chipper1 == "":
         print("Empty chipper is not allowed, try again...")
         print()
         continue
      break
   return(chipper1)

# Reset all parameters to False, "" or []
all = recursive = verbose = quiet = False
chipper = ""
directory = ""
files = []
allfiles = []

# Process arguments, I love argparse
desc = "This program encodes a file with a chipper. To decode it, you have to " + \
   "encode it again with the same chipper. A very simple encoding mechanism is " + \
   "used, so it can be broken easily, so do not trust it so much. But it " + \
   "might be used to hide documents on your computer\n" + \
   "You can supply a directory with -d option to include all files in it, " + \
   "add -r to traverse subdirectories, use -a to include hidden files. -v and" + \
   " -q are used for verbose and quite modes. With -c you can give you chipper " + \
   "eg. password at the command line, if you omit it you'll be asked for it by " + \
   "the program. Finally you can add filenames to encode"

# Start parser
parser = argparse.ArgumentParser(description="Encode", epilog=desc)

# Add 2 mutually exclusive options
#  verbose or quiet, one or none can be selected
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", help = "verbose output",
        action="store_true")
group.add_argument("-q", "--quiet", help = "quiet mode, no output",
        action="store_true")

# Optional argument for directory of the files to be renames
parser.add_argument("-d", "--directory", default="",
                    help="directory of the files to be renamed")
parser.add_argument("-c", "--chipper", default="",
                    help="chipper (password) for encoding")
parser.add_argument("-a", "--all", 
                    help="do not ignore entries starting with .", action="store_true")
parser.add_argument("-r", "--recursive", 
                    help="recurse subdirectories", action="store_true")

# Positional argument for the files to encode
parser.add_argument("files", nargs ="*",
        help = "Files to encode")

args = parser.parse_args()

directory = args.directory
chipper = args.chipper
all = args.all 
recursive = args.recursive
quiet = args.quiet
verbose = args.verbose
files = args.files

# Fill the file list from the given directory
if directory != "":
   traverse(directory)
# Add given files to the list
if files != []:
   for filename in files:
      if not os.path.isfile(filename):
         if not quiet:
            print(f"{filename} does not exist, skipping it")
      else:
         allfiles.append(filename)
# No files, nothing to do
if allfiles == []:
   print("No files to process, exiting...")
   exit(11)

# Number of files to process
if not quiet:
   print("Total ", len(allfiles), "files to process...")

# Chipper not given in arguments, ask it
if chipper == "":
   chipper = getchipper()

# Convert chipper text to bytes
chippers = bytearray(chipper, "utf-8")

# Encode all files
for filename in allfiles:
   ret = decen(filename)
   if not quiet:
      if ret == 11:
         sys.stdout.write("File ", filename, "does not exist or is not a file")
         sys.stdout.flush()
      elif ret == 12:
         sys.stdout.write("Unknown encode error on ", filename)
         sys.stdout.flush()
if not quiet:
   print("Done")

Posted in Python

Post navigation

Apache Fine Tunes on Ubuntu
Python3 MariaDB Programming
Proudly powered by WordPress | Theme: micro, developed by DevriX.