2018-10-19 12:48:28 +00:00
|
|
|
"""
|
2019-11-16 07:05:00 +00:00
|
|
|
author: Christian Bender
|
|
|
|
date: 21.12.2017
|
|
|
|
class: XORCipher
|
|
|
|
|
|
|
|
This class implements the XOR-cipher algorithm and provides
|
|
|
|
some useful methods for encrypting and decrypting strings and
|
|
|
|
files.
|
|
|
|
|
|
|
|
Overview about methods
|
|
|
|
|
|
|
|
- encrypt : list of char
|
|
|
|
- decrypt : list of char
|
|
|
|
- encrypt_string : str
|
|
|
|
- decrypt_string : str
|
|
|
|
- encrypt_file : boolean
|
|
|
|
- decrypt_file : boolean
|
2018-10-19 12:48:28 +00:00
|
|
|
"""
|
2021-09-22 21:11:51 +00:00
|
|
|
from __future__ import annotations
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
|
2020-01-03 14:25:36 +00:00
|
|
|
class XORCipher:
|
2020-10-16 06:11:52 +00:00
|
|
|
def __init__(self, key: int = 0):
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
simple constructor that receives a key or uses
|
|
|
|
default key = 0
|
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# private field
|
|
|
|
self.__key = key
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2021-04-04 05:22:12 +00:00
|
|
|
def encrypt(self, content: str, key: int) -> list[str]:
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
input: 'content' of type string and 'key' of type int
|
|
|
|
output: encrypted string 'content' as a list of chars
|
|
|
|
if key not passed the method uses the key by the constructor.
|
|
|
|
otherwise key = 1
|
2023-10-29 12:57:04 +00:00
|
|
|
|
|
|
|
Empty list
|
|
|
|
>>> XORCipher().encrypt("", 5)
|
|
|
|
[]
|
|
|
|
|
|
|
|
One key
|
|
|
|
>>> XORCipher().encrypt("hallo welt", 1)
|
|
|
|
['i', '`', 'm', 'm', 'n', '!', 'v', 'd', 'm', 'u']
|
|
|
|
|
|
|
|
Normal key
|
|
|
|
>>> XORCipher().encrypt("HALLO WELT", 32)
|
|
|
|
['h', 'a', 'l', 'l', 'o', '\\x00', 'w', 'e', 'l', 't']
|
|
|
|
|
|
|
|
Key greater than 255
|
|
|
|
>>> XORCipher().encrypt("hallo welt", 256)
|
|
|
|
['h', 'a', 'l', 'l', 'o', ' ', 'w', 'e', 'l', 't']
|
2020-09-10 08:31:26 +00:00
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# precondition
|
2023-10-11 18:30:02 +00:00
|
|
|
assert isinstance(key, int)
|
|
|
|
assert isinstance(content, str)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
key = key or self.__key or 1
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2021-09-22 21:11:51 +00:00
|
|
|
# make sure key is an appropriate size
|
2023-10-29 12:57:04 +00:00
|
|
|
key %= 256
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2021-09-22 21:11:51 +00:00
|
|
|
return [chr(ord(ch) ^ key) for ch in content]
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2021-04-04 05:22:12 +00:00
|
|
|
def decrypt(self, content: str, key: int) -> list[str]:
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
input: 'content' of type list and 'key' of type int
|
|
|
|
output: decrypted string 'content' as a list of chars
|
|
|
|
if key not passed the method uses the key by the constructor.
|
|
|
|
otherwise key = 1
|
2023-10-29 12:57:04 +00:00
|
|
|
|
|
|
|
Empty list
|
|
|
|
>>> XORCipher().decrypt("", 5)
|
|
|
|
[]
|
|
|
|
|
|
|
|
One key
|
|
|
|
>>> XORCipher().decrypt("hallo welt", 1)
|
|
|
|
['i', '`', 'm', 'm', 'n', '!', 'v', 'd', 'm', 'u']
|
|
|
|
|
|
|
|
Normal key
|
|
|
|
>>> XORCipher().decrypt("HALLO WELT", 32)
|
|
|
|
['h', 'a', 'l', 'l', 'o', '\\x00', 'w', 'e', 'l', 't']
|
|
|
|
|
|
|
|
Key greater than 255
|
|
|
|
>>> XORCipher().decrypt("hallo welt", 256)
|
|
|
|
['h', 'a', 'l', 'l', 'o', ' ', 'w', 'e', 'l', 't']
|
2020-09-10 08:31:26 +00:00
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# precondition
|
2023-10-11 18:30:02 +00:00
|
|
|
assert isinstance(key, int)
|
2023-10-29 12:57:04 +00:00
|
|
|
assert isinstance(content, str)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
key = key or self.__key or 1
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2021-09-22 21:11:51 +00:00
|
|
|
# make sure key is an appropriate size
|
2023-10-29 12:57:04 +00:00
|
|
|
key %= 256
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2021-09-22 21:11:51 +00:00
|
|
|
return [chr(ord(ch) ^ key) for ch in content]
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-10-16 06:11:52 +00:00
|
|
|
def encrypt_string(self, content: str, key: int = 0) -> str:
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
input: 'content' of type string and 'key' of type int
|
|
|
|
output: encrypted string 'content'
|
|
|
|
if key not passed the method uses the key by the constructor.
|
|
|
|
otherwise key = 1
|
2023-10-29 12:57:04 +00:00
|
|
|
|
|
|
|
Empty list
|
|
|
|
>>> XORCipher().encrypt_string("", 5)
|
|
|
|
''
|
|
|
|
|
|
|
|
One key
|
|
|
|
>>> XORCipher().encrypt_string("hallo welt", 1)
|
|
|
|
'i`mmn!vdmu'
|
|
|
|
|
|
|
|
Normal key
|
|
|
|
>>> XORCipher().encrypt_string("HALLO WELT", 32)
|
|
|
|
'hallo\\x00welt'
|
|
|
|
|
|
|
|
Key greater than 255
|
|
|
|
>>> XORCipher().encrypt_string("hallo welt", 256)
|
|
|
|
'hallo welt'
|
2020-09-10 08:31:26 +00:00
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# precondition
|
2023-10-11 18:30:02 +00:00
|
|
|
assert isinstance(key, int)
|
|
|
|
assert isinstance(content, str)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
key = key or self.__key or 1
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2023-10-29 12:57:04 +00:00
|
|
|
# make sure key is an appropriate size
|
|
|
|
key %= 256
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# This will be returned
|
|
|
|
ans = ""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
for ch in content:
|
|
|
|
ans += chr(ord(ch) ^ key)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
return ans
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-10-16 06:11:52 +00:00
|
|
|
def decrypt_string(self, content: str, key: int = 0) -> str:
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
input: 'content' of type string and 'key' of type int
|
|
|
|
output: decrypted string 'content'
|
|
|
|
if key not passed the method uses the key by the constructor.
|
|
|
|
otherwise key = 1
|
2023-10-29 12:57:04 +00:00
|
|
|
|
|
|
|
Empty list
|
|
|
|
>>> XORCipher().decrypt_string("", 5)
|
|
|
|
''
|
|
|
|
|
|
|
|
One key
|
|
|
|
>>> XORCipher().decrypt_string("hallo welt", 1)
|
|
|
|
'i`mmn!vdmu'
|
|
|
|
|
|
|
|
Normal key
|
|
|
|
>>> XORCipher().decrypt_string("HALLO WELT", 32)
|
|
|
|
'hallo\\x00welt'
|
|
|
|
|
|
|
|
Key greater than 255
|
|
|
|
>>> XORCipher().decrypt_string("hallo welt", 256)
|
|
|
|
'hallo welt'
|
2020-09-10 08:31:26 +00:00
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# precondition
|
2023-10-11 18:30:02 +00:00
|
|
|
assert isinstance(key, int)
|
|
|
|
assert isinstance(content, str)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
key = key or self.__key or 1
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2023-10-29 12:57:04 +00:00
|
|
|
# make sure key is an appropriate size
|
|
|
|
key %= 256
|
2019-08-06 10:14:23 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# This will be returned
|
|
|
|
ans = ""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
for ch in content:
|
|
|
|
ans += chr(ord(ch) ^ key)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
return ans
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-10-16 06:11:52 +00:00
|
|
|
def encrypt_file(self, file: str, key: int = 0) -> bool:
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
input: filename (str) and a key (int)
|
|
|
|
output: returns true if encrypt process was
|
|
|
|
successful otherwise false
|
|
|
|
if key not passed the method uses the key by the constructor.
|
|
|
|
otherwise key = 1
|
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# precondition
|
2023-10-11 18:30:02 +00:00
|
|
|
assert isinstance(file, str)
|
|
|
|
assert isinstance(key, int)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2023-10-29 12:57:04 +00:00
|
|
|
# make sure key is an appropriate size
|
|
|
|
key %= 256
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
try:
|
2023-03-01 16:23:33 +00:00
|
|
|
with open(file) as fin, open("encrypt.out", "w+") as fout:
|
|
|
|
# actual encrypt-process
|
|
|
|
for line in fin:
|
|
|
|
fout.write(self.encrypt_string(line, key))
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-10-21 10:46:14 +00:00
|
|
|
except OSError:
|
2019-10-05 05:14:13 +00:00
|
|
|
return False
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
return True
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-10-16 06:11:52 +00:00
|
|
|
def decrypt_file(self, file: str, key: int) -> bool:
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
input: filename (str) and a key (int)
|
|
|
|
output: returns true if decrypt process was
|
|
|
|
successful otherwise false
|
|
|
|
if key not passed the method uses the key by the constructor.
|
|
|
|
otherwise key = 1
|
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
# precondition
|
2023-10-11 18:30:02 +00:00
|
|
|
assert isinstance(file, str)
|
|
|
|
assert isinstance(key, int)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2023-10-29 12:57:04 +00:00
|
|
|
# make sure key is an appropriate size
|
|
|
|
key %= 256
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
try:
|
2023-03-01 16:23:33 +00:00
|
|
|
with open(file) as fin, open("decrypt.out", "w+") as fout:
|
|
|
|
# actual encrypt-process
|
|
|
|
for line in fin:
|
|
|
|
fout.write(self.decrypt_string(line, key))
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-10-21 10:46:14 +00:00
|
|
|
except OSError:
|
2019-10-05 05:14:13 +00:00
|
|
|
return False
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
return True
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
|
2023-10-29 12:57:04 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
from doctest import testmod
|
|
|
|
|
|
|
|
testmod()
|
|
|
|
|
2018-10-19 12:48:28 +00:00
|
|
|
# Tests
|
|
|
|
# crypt = XORCipher()
|
|
|
|
# key = 67
|
|
|
|
|
2020-10-17 07:56:11 +00:00
|
|
|
# # test encrypt
|
2019-08-06 10:14:23 +00:00
|
|
|
# print(crypt.encrypt("hallo welt",key))
|
2018-10-19 12:48:28 +00:00
|
|
|
# # test decrypt
|
2019-08-06 10:14:23 +00:00
|
|
|
# print(crypt.decrypt(crypt.encrypt("hallo welt",key), key))
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
# # test encrypt_string
|
2019-08-06 10:14:23 +00:00
|
|
|
# print(crypt.encrypt_string("hallo welt",key))
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
# # test decrypt_string
|
2019-08-06 10:14:23 +00:00
|
|
|
# print(crypt.decrypt_string(crypt.encrypt_string("hallo welt",key),key))
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
# if (crypt.encrypt_file("test.txt",key)):
|
2019-11-16 07:05:00 +00:00
|
|
|
# print("encrypt successful")
|
2018-10-19 12:48:28 +00:00
|
|
|
# else:
|
2019-11-16 07:05:00 +00:00
|
|
|
# print("encrypt unsuccessful")
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
# if (crypt.decrypt_file("encrypt.out",key)):
|
2019-11-16 07:05:00 +00:00
|
|
|
# print("decrypt successful")
|
2018-10-19 12:48:28 +00:00
|
|
|
# else:
|
2019-11-16 07:05:00 +00:00
|
|
|
# print("decrypt unsuccessful")
|