Last active
October 26, 2021 17:42
-
-
Save Frontear/45d2fa3da769841ae92d3fc2a0c29e3b to your computer and use it in GitHub Desktop.
A simple string obfuscation/deobfuscation python program. This was used as a non-secure, educational use only "encryption" for a school assignment.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import zlib | |
import base64 | |
import hashlib | |
SEPARATOR = "\0" | |
ENCODING = "UTF-8" | |
HASHING = hashlib.blake2b | |
def encrypt(data: str, key: str) -> bytes: | |
arr = [] | |
data = list(data) | |
key_hash = HASHING(key.encode(ENCODING)).hexdigest() | |
arr.append(key_hash) | |
for i in range(len(data)): | |
char, shift = ord(data[i]), ord(key[i % len(key)]) | |
enc = hex(char + shift) | |
arr.append(enc) | |
return base64.standard_b64encode(zlib.compress(SEPARATOR.join(arr).encode(ENCODING))) | |
def decrypt(data: bytes, key: str) -> str: | |
arr = [] | |
data = zlib.decompress(base64.standard_b64decode(data)).decode(ENCODING).split(SEPARATOR) | |
key_hash = HASHING(key.encode(ENCODING)).hexdigest() | |
if key_hash == data[0]: | |
for i in range(len(data := data[1:])): | |
char, shift = int(data[i], 16), ord(key[i % len(key)]) | |
dec = chr(char - shift) | |
arr.append(dec) | |
else: | |
raise InterruptedError("Given password was incorrect. Cannot decrypt") | |
return "".join(arr) | |
if __name__ == "__main__": | |
import string | |
data = string.printable | |
password = "ali4588" | |
with open("test.enc", "wb+") as f: | |
f.write(a := encrypt(data, password)) | |
print(a) | |
f.seek(0) | |
print(d := decrypt(f.read(), password)); assert d == data | |
# len(b) > len(c) | |
print(a := encrypt(b := "a ", c := "a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a ", c := "1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "1 ", c := "a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "1 ", c := "1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a1", c := "a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a1", c := "1"), d := decrypt(a, c)); assert b == d | |
#len(b) == len(c) | |
print(a := encrypt(b := "a ", c := "a1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a ", c := "1a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "1 ", c := "a1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "1 ", c := "1a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a1", c := "a1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a1", c := "1a"), d := decrypt(a, c)); assert b == d | |
#len(b) < len(c) | |
print(a := encrypt(b := " ", c := "a1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := " ", c := "1a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a", c := "a1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "a", c := "1a"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "1", c := "a1"), d := decrypt(a, c)); assert b == d | |
print(a := encrypt(b := "1", c := "1a"), d := decrypt(a, c)); assert b == d |
Decryption no longer silently fails, instead Errors.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The way this program works is fairly trivial. First, it requires data in the form of a string, and a password to secure said data. It hashes the password using the
blake2b
algo by default, storing itshexdigest()
for later usage. It then makes use of a cipher pattern similar to the vigenère cipher, creating a variation of the character shift table, by first obtaining theord
of each character, obtaining the correspondingord
character of the password (examples for reference below), then add the ordinal values of the characters, hex them, and then append them to an array. The array also, at the0th
index, contains thehexdigest
of the key, for comparision later on. Finally, the array is joined into a string separated bySEPARATOR
, encoded viaENCODING
, compressed through thezlib
module, and then encoded viabase64
.e.g.
The decryption process follows the exact reverse of the encryption process. It first decompresses the data, decodes it, and splits on the
SEPARATOR
. It first checks thehexdigest
in the first element. If the comparison fails, it silent fails with an empty string as its return data. Otherwise, it obtains the ordinal number from the data, the corresponding key character ordinal, and subtracts to obtain the original character ordinal. It then converts that into an actual character, appending it to an array. Finally, the array is joined with no separator into the decrypted data.The code above contains a large chunk of testing code used to validify the operation of the code via various input lengths. It also attempts to write and read from a file (largely due to the fact that this was a part of the assignment constraints.)
Please note that this is not secure in any capacity. It cannot cryptographically secure any data. The only reason I ended up realistically writing this code was a) to understand and experiment with obfuscating strings, and b) because the assignment constraints prohibited modules from outside the standard library. As such, I could not use any crypto libs, or otherwise this wouldn't have had to be written. Nonetheless, its good for future references and is actually not a terrible way to obfuscate data, as in the end, the data is only meant to not be legible by people, not be secured.