def convert(self, source='index.karp', dist='index.html'): if source not in self.graph.links: file_worker = FileWorker() content = file_worker.read(source) converted_content = self.parse(content, source) file_worker.write(dist, converted_content)
def __init__(self, verbose=False): """ Initialize Crypter class """ self.config = None self.acl = None self.roles = None self.users = None self.files = [] # for future use self.web_pages = [] self.dir = None self.tempdir = None self.verbose = verbose self.fileworker = FileWorker()
class Searcher: def __init__(self): self.file_worker = FileWorker() def search(self, graph, text): n = len(graph.links) used = [False] * n result = [] def runner(child, node): if used[child] == True: return False path = graph.ids[child] used[child] = True doc = self.file_worker.read(path) if self.find_text(text, doc): result.append(path) return True for i in range(len(used)): if not used[i]: graph.dfs(i, None, runner, used) return result def find_text(self, text, doc): return doc.find(text) != -1
def __init__(self, file): """ Init Roles class """ self.list = [] self.encrypted_list = [] self.file = file self.fileworker = FileWorker() # Try open file with unkown encoding (BOM is problem roles = self.fileworker.open_json_file(file) if roles == None: print("Error: Can't open or parse '" + file + "'. Please, check file format.") exit(100) for role in roles: self.add_role(role)
def __init__(self, pending_events, active_events, ical_file): super().__init__() self.file_worker = FileWorker(pending_events, active_events, ical_file, passed_todos='work_files/passed_events.txt') self.ical_file = ical_file
class EventOrganizer(EventScheduler): def __init__(self, pending_events, active_events, ical_file): super().__init__() self.file_worker = FileWorker(pending_events, active_events, ical_file, passed_todos='work_files/passed_events.txt') self.ical_file = ical_file def add_event(self, start_date, deadline_date, name, message, timezone='local'): try: event = EventScheduler.add_event(self, start_date, deadline_date, name, message, timezone) self.file_worker.add_todo(event) except InvalidDateError: raise def remove_event(self, target_id): result = EventScheduler.remove_by_id(self, target_id) if result: self.file_worker.update_all_files(self.enumerate_todos(), self.sorted_events()) return result def load_saved_events(self): '''Should be called when the app starts to filter the saved events''' self.load_saved_active_events() self.load_saved_pending_events() def load_saved_active_events(self): events = self.file_worker.get_saved_active_todos() filtered = self.filter_passed_events(events) EventScheduler.add_multiple_active_events(self, filtered[0]) self.file_worker.update_passed_todos(filtered[2]) self.file_worker.update_active_file(self.sorted_events()) def load_saved_pending_events(self): todos = self.file_worker.get_saved_pending_todos() filtered = self.filter_passed_events(todos) EventScheduler.add_multiple_active_events(self, filtered[0]) EventScheduler.add_multiple_pending_events(self, filtered[1]) self.file_worker.update_passed_todos(filtered[2]) self.file_worker.update_all_files(self.enumerate_todos(), self.sorted_events()) def filter_passed_events(self, todos): passed_events = [] active_events = [] pending_events = [] for todo in todos: if self.passed_date(todo.deadline_datetime): passed_events.append(todo) elif self.passed_date(todo.start_datetime): active_events.append(todo) else: pending_events.add(todo) return (active_events, pending_events, passed_events) def activate_pending_event(self, event): EventScheduler.activate_event(self, event) self.file_worker.update_all_files(self.enumerate_todos(), self.sorted_events()) def expire_active_event(self, event): EventScheduler.expire_active_event(self, event) self.file_worker.update_all_files(self.enumerate_todos(), self.sorted_events()) def handle_events(self, events): '''This function does the actual work with the events.''' expired = [] active = [] for event in events: if event.mode is 'pending': active.append(event) elif event.mode is 'active': expired.append(event) print(active) print(expired) self.activate_pending_events(active) self.expire_active_events(expired) def activate_pending_events(self, events): for event in events: self.activate_pending_event(event) def expire_active_events(self, events): for event in events: self.expire_active_event(event) def sorted_events(self): return sorted(self.active_events, key=lambda e: e.deadline_datetime) def export_ical(self): self.file_worker.update_ical_file(self.active_events) def has_moment(self, moment): for key in self.todos.keys(): if key.to('utc') < moment.to('utc') or key.to('utc') is moment.to('utc'): return True return False def handle_moment(self, moment): '''This function should be called when the moment has just happened.''' for key in self.todos.keys(): if key.to('utc') < moment.to('utc'): print("in handle_moment") self.handle_events(self.todos[key])
def __init__(self): self.file_worker = FileWorker()
class Config(object): """ Config file Json config file properties: ============================ { "site-name": "J3A Demo", "uri-base": "https://praserx.github.io/j3a/demo", // Required "uri-boot": "security/boot.script.html", // Required "uri-acl": "security/acl.json", // Required "uri-roles": "security/roles.json", // Required "uri-version": "security/version.json", // Required "uri-users-dir": "security/users", // Required "uri-resources-dir": "security/resources", // Required "denied-info-element": "security/deniedWarning.html", // Required "denied-info-page": "security/denied.html", // Required "allow-cache": "true", // Recommended, default: true "auto-logout": "true", // Not supported, default: false "algorithms": { // Recommended "public-key-encryption": "RSA-OAEP", // Recommended, default: RSA-OAEP "private-key-encryption": "AES-GCM", // Recommneded, default: AES-GCM "digest": "SHA-512", // Recommended, default: SHA-512 "sign": "", // Not supported "key-derivation": "PBKDF2" // Recommended, default: PBKDF2 }, "perm-groups": [], // Not supported "file-perm-groups": [] // Not supported } """ def __init__(self, file, base_dir): """ Init Config class """ self.fileworker = FileWorker() # Main properties (required) self.uri_base = base_dir self.uri_boot = None self.uri_acl = None self.uri_roles = None self.uri_version = None self.uri_users_dir = None self.uri_resources_dir = None self.denied_info_element = None self.denied_info_page = None # Algorithm properties (recommended) self.public_key_encryption = None self.private_key_encryption = None self.digest = None self.sign = None self.key_derivation = None # Try open file with unkown encoding (BOM is problem) conf = self.fileworker.open_json_file(file) if conf == None: print("Error: Can't open or parse", file, "Please, check file format.") exit(100) # Check config file required properties if not ("uri-boot" in conf): print("Error: Bad config file structure! Missing: 'uri-boot'") exit(100) if not ("uri-acl" in conf): print("Error: Bad config file structure! Missing: 'uri-acl'") exit(100) if not ("uri-roles" in conf): print("Error: Bad config file structure! Missing: 'uri-roles'") exit(100) if not ("uri-version" in conf): print("Error: Bad config file structure! Missing: 'uri-version'") exit(100) if not ("uri-users-dir" in conf): print("Error: Bad config file structure! Missing: 'uri-users-dir'") exit(100) if not ("uri-resources-dir" in conf): print( "Error: Bad config file structure! Missing: 'uri-resources-dir'" ) exit(100) if not ("denied-info-element" in conf): print( "Error: Bad config file structure! Missing: 'denied-info-element'" ) exit(100) if not ("denied-info-page" in conf): print( "Error: Bad config file structure! Missing: 'denied-info-page'" ) exit(100) # Set config file properties self.uri_boot = conf["uri-boot"] self.uri_acl = conf["uri-acl"] self.uri_roles = conf["uri-roles"] self.uri_version = conf["uri-version"] self.uri_users_dir = conf["uri-users-dir"] self.uri_resources_dir = conf["uri-resources-dir"] self.denied_info_element = conf["denied-info-element"] # Set algorithms if ("algorithms" in conf): if ("public-key-encryption" in conf["algorithms"]): self.public_key_encryption = conf["algorithms"][ "public-key-encryption"] if ("private-key-encryption" in conf["algorithms"]): self.private_key_encryption = conf["algorithms"][ "private-key-encryption"] if ("digest" in conf["algorithms"]): self.digest = conf["algorithms"]["digest"] if ("sign" in conf["algorithms"]): self.sign = conf["algorithms"]["sign"] if ("key-derivation" in conf["algorithms"]): self.key_derivation = conf["algorithms"]["key-derivation"] def check_config(self, prefix): """ Check config required properties """ if (self.public_key_encryption == "") or (self.public_key_encryption == None): print( prefix, "'config.json'" + " 'public-key-encryption' in 'algoritms' is not defined.") if (self.private_key_encryption == "") or (self.private_key_encryption == None): print( prefix, "'config.json'" + " 'private-key-encryption' in 'algoritms' is not defined.") if (self.digest == "") or (self.digest == None): print(prefix, "'config.json'" + " 'digest' in 'algoritms' is not defined.") if (self.sign == "") or (self.sign == None): print(prefix, "'config.json'" + " 'sign' in 'algoritms' is not defined.") if (self.key_derivation == "") or (self.key_derivation == None): print( prefix, "'config.json'" + " 'key-derivation' in 'algoritms' is not defined.")
def __init__(self, file, base_dir): """ Init Config class """ self.fileworker = FileWorker() # Main properties (required) self.uri_base = base_dir self.uri_boot = None self.uri_acl = None self.uri_roles = None self.uri_version = None self.uri_users_dir = None self.uri_resources_dir = None self.denied_info_element = None self.denied_info_page = None # Algorithm properties (recommended) self.public_key_encryption = None self.private_key_encryption = None self.digest = None self.sign = None self.key_derivation = None # Try open file with unkown encoding (BOM is problem) conf = self.fileworker.open_json_file(file) if conf == None: print("Error: Can't open or parse", file, "Please, check file format.") exit(100) # Check config file required properties if not ("uri-boot" in conf): print("Error: Bad config file structure! Missing: 'uri-boot'") exit(100) if not ("uri-acl" in conf): print("Error: Bad config file structure! Missing: 'uri-acl'") exit(100) if not ("uri-roles" in conf): print("Error: Bad config file structure! Missing: 'uri-roles'") exit(100) if not ("uri-version" in conf): print("Error: Bad config file structure! Missing: 'uri-version'") exit(100) if not ("uri-users-dir" in conf): print("Error: Bad config file structure! Missing: 'uri-users-dir'") exit(100) if not ("uri-resources-dir" in conf): print( "Error: Bad config file structure! Missing: 'uri-resources-dir'" ) exit(100) if not ("denied-info-element" in conf): print( "Error: Bad config file structure! Missing: 'denied-info-element'" ) exit(100) if not ("denied-info-page" in conf): print( "Error: Bad config file structure! Missing: 'denied-info-page'" ) exit(100) # Set config file properties self.uri_boot = conf["uri-boot"] self.uri_acl = conf["uri-acl"] self.uri_roles = conf["uri-roles"] self.uri_version = conf["uri-version"] self.uri_users_dir = conf["uri-users-dir"] self.uri_resources_dir = conf["uri-resources-dir"] self.denied_info_element = conf["denied-info-element"] # Set algorithms if ("algorithms" in conf): if ("public-key-encryption" in conf["algorithms"]): self.public_key_encryption = conf["algorithms"][ "public-key-encryption"] if ("private-key-encryption" in conf["algorithms"]): self.private_key_encryption = conf["algorithms"][ "private-key-encryption"] if ("digest" in conf["algorithms"]): self.digest = conf["algorithms"]["digest"] if ("sign" in conf["algorithms"]): self.sign = conf["algorithms"]["sign"] if ("key-derivation" in conf["algorithms"]): self.key_derivation = conf["algorithms"]["key-derivation"]
class RoleList(object): """ Roles class defined in roles.json """ def __init__(self, file): """ Init Roles class """ self.list = [] self.encrypted_list = [] self.file = file self.fileworker = FileWorker() # Try open file with unkown encoding (BOM is problem roles = self.fileworker.open_json_file(file) if roles == None: print("Error: Can't open or parse '" + file + "'. Please, check file format.") exit(100) for role in roles: self.add_role(role) def save(self): """ Save roles to file """ file = codecs.open(self.file, "w+", "utf-8") json_output = [] for role in self.encrypted_list: json_output.append({ "role": role.name, "inherits": role.inherits, "secret": role.secret }) json.dump(json_output, file) file.close() def add_role(self, role_json): """ Append Role object to list """ if not ("role" in role_json): print("Error: File format error. Missing 'role' in json array.") exit(100) if "inherits" in role_json: self.list.append(Role(role_json["role"], role_json["inherits"])) else: self.list.append(Role(role_json["role"])) def add_encrypted_role(self, role: Role): """ Append Role object with encrypted secret to list """ self.encrypted_list.append(role) def add_ack_to_role(self, resource_id: str, permissions: str, secret): """ Set secret (unencrypted) to role """ for permission in permissions: # Create secret item (resource) resource = {"resource_id": resource_id, "secret": secret} role = self.get_role_by_name(permission).secret.append(resource) def compute_heredity(self): """ Some roles has heredity, we have to copy some resources to ensure access """ for role in self.list: for irole in self.get_complete_inheritance(role, []): oirole = self.get_role_by_name( irole) # irole object (role_src) self.duplicate_resources( role, oirole) # role = role_dest, oirole = role_src def duplicate_resources(self, role_dest, role_src): """ Duplicate resources from one role to other """ if role_src == None: return for role_src_resource in role_src.secret: rcs = False for role_dest_resource in role_dest.secret: if role_src_resource["resource_id"] == role_dest_resource[ "resource_id"]: rcs = True if rcs == False: role_dest.secret.append(role_src_resource) def get_complete_inheritance(self, role: Role, ilist): """ Computes complete inheritance """ new = False for irole in role.inherits: if not (irole in ilist): new = True ilist.append(irole) if new == True: new = False ilist = self.get_complete_inheritance( self.get_role_by_name(irole), ilist) return ilist def role_dependancy_check(self): """ Check role dependency (find unknown role names) """ roles = [] inher = [] for role in self.list: roles.append(role.name) for role in self.list: inher.extend(role.inherits) for i in inher: if not (i in roles): return i return None def get_role_by_name(self, role_name): """ Return role by role name """ for role in self.list: if role_name == role.name: return role return None
class Crypter: """ Main class providing cryptographic function and processing input directories """ # Supported algorithms SUPP_ALGS = { "public-key-encryption": ["RSA-OAEP"], "private-key-encryption": ["AES-GCM"], "digest": ["SHA-256", "SHA-512"], "sign": [], "key-derivation": ["PBKDF2"] } # Default algoritms DEFAULT_ALGS = { "public-key-encryption": "RSA-OAEP", "private-key-encryption": "AES-GCM", "digest": "SHA-512", "sign": "", "key-derivation": "PBKDF2" } def __init__(self, verbose=False): """ Initialize Crypter class """ self.config = None self.acl = None self.roles = None self.users = None self.files = [] # for future use self.web_pages = [] self.dir = None self.tempdir = None self.verbose = verbose self.fileworker = FileWorker() def initialize(self, src, dest): """ Initialize destination directory """ if self.verbose: print("[FINALIZE] Purifying destination directory") # Destination folder does not exists if os.path.isdir(dest): self.init_dest_dir(dest) if self.verbose: print( "[INITIALIZE] Define temporary directory 'j3a_crypter_temp' in system 'temp' directory" ) # Create temporary directory in system temp location self.tempdir = tempfile.gettempdir() + '/j3a_crypter_temp' if os.path.isdir(self.tempdir): self.init_dest_dir(self.tempdir) if self.verbose: print( "[INITIALIZE] Copying content of source directory to temporary directory" ) self.copy_src_to_dest(src, self.tempdir) def analyze(self): """ Analyze destination directory, load files and index web pages """ self.dir = self.tempdir dir = self.tempdir # Index config file for file in os.listdir(dir): if file == "config.json": # Load config file self.config = Config(os.path.join(dir + '\\', file), dir) # Check config instance if self.config == None: print( "Error: Can not find 'config.json'. File has to be in web page root directory." ) exit(100) if self.verbose: print("[ANALYZE] Config has been loaded") # Check config file for required values if self.verbose: self.config.check_config("[ANALYZE][WARNING]") # Load acl file self.acl = Acl( os.path.join(dir + '/', self.config.uri_acl).replace("\\", "/")) if self.verbose: print("[ANALYZE] ACL has been loaded") # Load roles file self.roles = RoleList( os.path.join(dir + '/', self.config.uri_roles).replace("\\", "/")) if self.verbose: print("[ANALYZE] Roles has been loaded") # Load users files if not os.path.isdir( dir.replace("\\", "/") + "/" + self.config.uri_users_dir): if self.verbose: print( "[ANALYZE][ERROR] Users database directory has not been specified correctly" ) print("Error: Users directory not found") exit(100) self.users = UserList( os.path.join(dir + '/', self.config.uri_users_dir).replace("\\", "/"), self.roles) if self.verbose: print("[ANALYZE] Users has been loaded") # Scan directories and get all web pages self.web_pages = self.scan_directory(dir) if self.verbose: print("[ANALYZE] Web pages has been indexed") for page in self.web_pages: print("[ANALYZE][PAGE] " + page) def process(self): """ Analyze and encrypt web pages and their parts or encrypt files This is quite confusing, what we going to do? It is not needed to describe Algorithm compatibility check and Resource directory check. What we have to describe is encryption of some files. First step: - we have to encrypt specified elements of web pages and this new ciphertext save to json file with his own ID - we have to generate new encrypted element tag and replace this original content by this tag Second step: - we have to encrypt "secret" of each ACL resource (list item) which contains cryptokeys of encrypted web pages - after that we have to save ACL to file and store new generated cryptokeys in some variable Third step: - we have to encrypt "secret" of each role which contains cryptokeys of encrypted ACL reources - after that we have to save roles to file and store new generated cryptokeys in some variable Fourth step: - this is almost end of process - we have to encrypt user confident data, so it is encrypted by specified pass or pub key certificate Fifth step: - we have to create version file. Why? Because of cache. We caching some files as config, acl or roles, so we have to know when reload these files - version file contains olny time constant, which describes last modification of resources and config files """ # Algorithm compatibility check if not self.algorithm_compatibility_check(): print("Error: Some of specified algorithm is not supported.") self.print_algorithm_support() exit(100) # Roles dependancy check dcheck = self.roles.role_dependancy_check() if dcheck != None: print("Error: Inheritance miss match! Role not found: " + dcheck) exit(100) # Resources directory check if not os.path.isdir(self.config.uri_base + "/" + self.config.uri_resources_dir): os.mkdir(self.config.uri_base + "/" + self.config.uri_resources_dir) if self.verbose: print("[PROCESS] Directory '" + self.config.uri_resources_dir + "' has been created") # Init variables content = None perm = None oda = None # First step: Encrypt web pages or their parts and save crytpo keys and info in ACL for loc in self.web_pages: error = False # At first try open as BOM, as a second try standard UTF-8 web_page = self.fileworker.open_file(loc) if web_page == None: print("Warning: Can't process " + loc) error = True if error == False: self.process_web_page(loc, web_page.read()) # Second step: Generate ACL file acl_cryptokeys = [] for resource in self.acl.resources: # resource.secret contains cryptokey from web page promise = self.encrypt( json.dumps(resource.secret) ) # ACL resource secret encryption (json.dumps --> json in string form) self.acl.add_encrypted_resource( AclResource(resource.id, resource.uri, resource.access, resource.permission, promise["ciphertext"])) acl_cryptokeys.append({ "resource_id": resource.id, "permission": resource.permission, "secret": promise["secret"] }) self.acl.save() if self.verbose: print("[PROCESS] ACL has been generated") # Third step: Generate Roles file for ack in acl_cryptokeys: # ack["secret"] contains cryptokey from ACL resource self.roles.add_ack_to_role( ack["resource_id"], ack["permission"], ack["secret"]) # ack == ACL cryptokey from ACL resource self.roles.compute_heredity( ) # Some roles has heredity, so we have to copy some resources to ensure access role_cryptokeys = [] for role in self.roles.list: promise = self.encrypt(json.dumps( role.secret)) # RoleList Role secret encryption self.roles.add_encrypted_role( Role(role.name, role.inherits, promise["ciphertext"])) role_cryptokeys.append({ "role": role.name, "secret": promise["secret"] }) self.roles.save() if self.verbose: print("[PROCESS] Roles has been generated") # Fourth step: Generate user database files and encrypt them with specific keys for rck in role_cryptokeys: #rck["secret"] contains cryptokey from Role self.users.add_rck_to_user(rck["role"], rck["secret"]) for user in self.users.list: if user.key_type == "password": # PBKDF2 #promise_pwd = self.pbkdf2(user.password) #promise = self.encrypt(json.dumps(user.secret), promise_pwd["ciphertext"], user.key_type) # Users User secret encryption by password #self.users.add_encrypted_user(EncryptedUser(user.username, user.roles, promise["ciphertext"], promise["secret"]["algorithm"], promise_pwd["salt"])) # Simple SHA-256 promise_pwd = self.sha256(user.password) promise = self.encrypt( json.dumps(user.secret), promise_pwd, user.key_type) # Users User secret encryption by password self.users.add_encrypted_user( EncryptedUser(user.username, user.roles, promise["ciphertext"], promise["secret"]["algorithm"], "")) elif user.key_type == "certificate": promise = self.encrypt(json.dumps( user.secret)) # Users User secret encryption by password encryptedUser = EncryptedUser(user.username, user.roles, promise["ciphertext"], promise["secret"]["algorithm"], "") promisersa = self.encrypt(promise["secret"]["key"], user.certificate, "certificate") encryptedUser.key_secret = promisersa encryptedUser.key_algorithm = {"name": "RSA-OAEP"} self.users.add_encrypted_user(encryptedUser) else: print( "[PROCESS][WARNING] Something goes wrong with user encryption. Be prepared for everything." ) self.users.save() if self.verbose: print("[PROCESS] Users has been generated") # We have to generate version.json which specify when was everything generated # (why? because we want to sometimes) refresh all cached data! version_file = codecs.open( self.config.uri_base.replace("\\", "/") + "/" + self.config.uri_version, "w+") json.dump( { "page-version": datetime.datetime.timestamp(datetime.datetime.now()) }, version_file) version_file.close() if self.verbose: print("[PROCESS] Version file has been generated") def finalize(self, dest): """ Finalize - copy files from temp dir to dest dir """ if self.verbose: print( "[FINALIZE] Copying content of temporary directory to destination directory" ) self.copy_src_to_dest(self.tempdir, dest) rmtree(self.tempdir) def init_dest_dir(self, dest): """ Remove content of destination directory """ rmtree(dest) def copy_src_to_dest(self, src, dest): """ Copy source directory to destination directory """ copytree(src, dest) def algorithm_compatibility_check(self): """ Check selected cryptography algorithms for availability. If ok return true, or else return false """ # Private if (self.config.private_key_encryption == "") or (self.config.private_key_encryption == None): self.config.private_key_encryption = self.DEFAULT_ALGS[ "private-key-encryption"] else: if not (self.config.private_key_encryption in self.SUPP_ALGS["private-key-encryption"]): return False # Public if (self.config.public_key_encryption == "") or (self.config.public_key_encryption == None): self.config.public_key_encryption = self.DEFAULT_ALGS[ "public-key-encryption"] else: if not (self.config.public_key_encryption in self.SUPP_ALGS["public-key-encryption"]): return False # Digest if (self.config.digest == "") or (self.config.digest == None): self.config.digest = self.DEFAULT_ALGS["digest"] else: if not (self.config.digest in self.SUPP_ALGS["digest"]): return False # Sign if (self.config.sign == "") or (self.config.sign == None): self.config.sign = self.DEFAULT_ALGS["sign"] else: if not (self.config.sign in self.SUPP_ALGS["sign"]): return False # Key derivation if (self.config.key_derivation == "") or (self.config.key_derivation == None): self.config.key_derivation = self.DEFAULT_ALGS["key-derivation"] else: if not (self.config.key_derivation in self.SUPP_ALGS["key-derivation"]): return False return True def print_algorithm_support(self): """ Print algorithm support help """ print("Supported algorithms:") public = "" for item in self.SUPP_ALGS["public-key-encryption"]: public += item + " " print(" public key encryption: " + public) private = "" for item in self.SUPP_ALGS["private-key-encryption"]: private += item + " " print(" private key encryption: " + private) digest = "" for item in self.SUPP_ALGS["digest"]: digest += item + " " print(" digest: " + digest) sign = "" for item in self.SUPP_ALGS["sign"]: sign += item + " " print(" sign: " + sign) derivation = "" for item in self.SUPP_ALGS["key-derivation"]: derivation += item + " " print(" key derivation: " + derivation) def scan_directory(self, dir): """ Scan whole directory and subdirectories and find all html and htm files with web content and return list of files """ files = [] # Index remaining files for entry in os.scandir(dir): # If if entry.is_dir(): files += self.scan_directory( os.path.join(dir + '\\', entry.name).replace("\\", "/")) # Search for html files if entry.name.endswith(".html") or entry.name.endswith(".htm"): files.append( os.path.join(dir + '\\', entry.name).replace("\\", "/")) return files def process_web_page(self, loc, web_page): """ Process web page (get data and perform encryption) """ if self.verbose: print("[PROCESS][PAGE] " + loc) # Get content for encryption contents = re.findall(r'<!--EE:BEGIN-->(.*?)<!--EE:END-->', web_page, re.DOTALL) if self.verbose and len(contents) == 0: print("[PROCESS][PAGE][INFO] No encrypted element found") # Encryption element id in current document ee_id = 1 page_divisions = [] for ee in contents: if self.verbose: print( "[PROCESS][PAGE][INFO] Encrypted element has been found! ID: " + str(ee_id)) # Get post processing info perm_list = re.findall(r'<!--PERM:(.*?)-->', ee) oda_list = re.findall(r'<!--ODA:(.*?)-->', ee) # Remove remove post processing info ee = re.sub(r'<!--PERM:(.*?)-->', '', ee) ee = re.sub(r'<!--ODA:(.*?)-->', '', ee) resource_uri = re.sub(self.dir.replace("\\", "/") + '/', '', loc) resource_id = self.sha256(resource_uri + '.' + str(ee_id)) # Get permissions permissions_chaos = perm_list[0].split(",") permissions = [] for perm in permissions_chaos: permissions.append(perm.rstrip().lstrip()) # Get ODA (on denied action) oda = oda_list[0].rstrip().lstrip() promise = self.encrypt(ee) # Define access if len(permissions) == 0: access = "public" else: access = "private" # Add new ACL resources self.acl.add_resource( AclResource(resource_id, resource_uri, access, permissions, promise["secret"])) page_division = { "ee_id": ee_id, "resource_id": resource_id, "ciphertext": promise["ciphertext"], "oda": oda } page_divisions.append(page_division) if self.verbose: print("[PROCESS][PAGE][INFO] Resource has been saved! ID: " + resource_id) ee_id += 1 # Update web page and save ciphertext file self.save_wp(loc, web_page, page_divisions) if self.verbose: print("[PROCESS][PAGE][INFO] File has been updated") return def save_wp(self, loc, page, divisions): """ Add encrypted element to page and save new content to file """ if self.config.uri_boot in loc: return if self.config.denied_info_element in loc: return wpcontent = page # Add boot script to page start = re.search(r'</body>', wpcontent, re.DOTALL).start() wpcontent = wpcontent[:start] + self.create_boot_element( ) + wpcontent[start:] for pd in divisions: pattern = re.compile(r'<!--EE:BEGIN-->(.*?)<!--EE:END-->', flags=re.DOTALL) start = re.search(r'<!--EE:BEGIN-->(.*?)<!--EE:END-->', wpcontent, re.DOTALL).start() wpcontent = re.sub(pattern, '', wpcontent, 1) # Add encrypted element to page wpcontent = wpcontent[:start] + self.create_encrypted_element( pd["resource_id"], pd["oda"]) + wpcontent[start:] # Save json file with encrypted element ctfile = codecs.open( self.config.uri_base.replace("\\", "/") + "/" + self.config.uri_resources_dir + '/' + pd["resource_id"] + ".json", "w+") json.dump({"ciphertext": pd["ciphertext"]}, ctfile) ctfile.close() # Save web page (edited) file = codecs.open(loc, "w+", "utf-8") file.write(wpcontent) file.close() def create_encrypted_element(self, resource_id, oda): """ Return generated encrypted element """ return '<encrypted-element resource-id="' + resource_id + '" oda="' + oda + '"></encrypted-element>\n' def create_boot_element(self): """ Returns generated boot script element """ ctfile = codecs.open( self.config.uri_base.replace("\\", "/") + "/" + self.config.uri_boot, "r") content = ctfile.read() ctfile.close() return content def hex_to_bytes(self, hex_string): """ Convert HEX string to bytes """ return base64.b16decode(hex_string.encode()) def encrypt(self, plaintext, key=None, key_type=None): """ Encrypt plaintext and return ciphertext and secret (crypto key, iv, ...) """ if (key == None): cipher = self.config.private_key_encryption elif (key != None) and (key_type == "password"): cipher = self.config.private_key_encryption elif (key != None) and (key_type == "certificate"): cipher = self.config.public_key_encryption else: return None if cipher == "AES-GCM": return self.aes_gcm(plaintext, key) elif cipher == "RSA-OAEP": return self.rsa_oaep(plaintext, key) return None def aes_gcm(self, plaintext, key=None): """ Perform AES GCM encryption and return pair secret and ciphertext """ # Backend setting backend = default_backend() # Init vector and key iv = os.urandom(16) if key == None: key = os.urandom(32) else: key = base64.b16decode(key.encode()) # Cipher text cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=backend) encryptor = cipher.encryptor() ciphertext = encryptor.update(bytes( plaintext.encode('UTF-8'))) + encryptor.finalize() # Set secret secret = { "algorithm": { "name": "AES-GCM", "iv": base64.b16encode(iv).decode(), "tag": len(encryptor.tag) * 8 }, "key": base64.b16encode(key).decode() } return { "secret": secret, "ciphertext": base64.b16encode(ciphertext).decode() + base64.b16encode(encryptor.tag).decode() } def rsa_oaep(self, plaintext, key=None): """ Perform RSA-OAEP encryption """ public_key = None with open( os.path.join(self.dir + '/' + self.config.uri_users_dir + '/', key).replace("\\", "/"), "rb") as key_file: public_key = serialization.load_pem_public_key( key_file.read(), backend=default_backend()) ciphertext = public_key.encrypt( bytes(plaintext.encode('UTF-8')), padding.OAEP(mgf=padding.MGF1(algorithm=SHA256()), algorithm=SHA256(), label=None)) return base64.b16encode(ciphertext).decode() def sha256(self, plaintext): """ Perform SHA-256 hash """ digest = Hash(SHA256(), backend=default_backend()) digest.update(bytes(plaintext.encode('UTF-8'))) hash = digest.finalize() #return binascii.hexlify(bytearray(hash)) return base64.b16encode(hash).decode() def sha512(self, plaintext): """ Perform SHA-512 hash """ digest = Hash(SHA512(), backend=default_backend()) digest.update(bytes(plaintext.encode('UTF-8'))) hash = digest.finalize() #return binascii.hexlify(bytearray(hash)) return base64.b16encode(hash).decode() def pbkdf2(sefl, plaintext): """ Perform PBKDF2 """ backend = default_backend() salt = os.urandom(16) kdf = PBKDF2HMAC(algorithm=SHA256(), length=32, salt=salt, iterations=1000, backend=backend) key = kdf.derive(bytes(plaintext.encode('UTF-8'))) return { "salt": base64.b16encode(salt).decode(), "ciphertext": base64.b16encode(key).decode() }