120 lines
No EOL
3 KiB
Python
120 lines
No EOL
3 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import click
|
|
from random import randint
|
|
from random import random
|
|
|
|
####################################################
|
|
##### Example Execution
|
|
# $ pip3 install click
|
|
# $ chmod +x ./obfuscate.py
|
|
# $ ./obfuscate.py "Hello World" --manglecase --dirac-max=5
|
|
# Input "Hello World"
|
|
#
|
|
# Output "ĥ̻͈̏̔ē͋͆͞ŀ͓̦̈́Ľ͎̖̃̉̈Ŏ̷͕̽͢ ̑͢Ẁ̻̈́ŏ̀̌͌͐ŕ̳ͥ͛̉͝ĺ̟̇ͦĐ̥̄ͭ̀͡"
|
|
#
|
|
# $
|
|
####################################################
|
|
|
|
@click.command()
|
|
@click.option('--no-manglecase/--manglecase', default=True)
|
|
@click.option('--dirac-min', default=2, type=click.IntRange(0,100))
|
|
@click.option('--dirac-max', default=14, type=click.IntRange(0,100))
|
|
@click.option('--unmangle-probability', default=0.1, type=click.FloatRange(0,1))
|
|
@click.argument('clean_string')
|
|
def mangle(clean_string, no_manglecase, dirac_min, dirac_max, unmangle_probability):
|
|
print(f'Input "{clean_string}"\n')
|
|
respect_case = no_manglecase
|
|
|
|
mangled_string = ''
|
|
for clean_letter in clean_string:
|
|
new_letter = mangle_letter(clean_letter,
|
|
unmangle_probability=unmangle_probability,
|
|
respect_case=respect_case)
|
|
if dirac_max < 0:
|
|
dirac_max = 0
|
|
if dirac_min < 0:
|
|
dirac_min = 0
|
|
if dirac_min > dirac_max:
|
|
dirac_min = dirac_max
|
|
new_letter += get_diracs(randint(dirac_min,dirac_max))
|
|
mangled_string += new_letter
|
|
|
|
print(f'Output "{mangled_string}"\n')
|
|
|
|
def mangle_letter(letter_raw,
|
|
unmangle_probability: float = 0.10,
|
|
respect_case: bool = True) -> str:
|
|
scope = (-1, -1)
|
|
letter = letter_raw.lower()
|
|
if letter == 'a':
|
|
scope = (0x00, 0x05)
|
|
elif letter == 'c':
|
|
scope = (0x06, 0x0D)
|
|
elif letter == 'd':
|
|
scope = (0x0E, 0x11)
|
|
elif letter == 'e':
|
|
scope = (0x12, 0x1B)
|
|
elif letter == 'g':
|
|
scope = (0x1C, 0x23)
|
|
elif letter == 'h':
|
|
scope = (0x24, 0x27)
|
|
elif letter == 'i':
|
|
scope = (0x28, 0x31)
|
|
elif letter == 'j':
|
|
scope = (0x34, 0x35)
|
|
elif letter == 'k':
|
|
scope = (0x36, 0x37)
|
|
elif letter == 'l':
|
|
scope = (0x39, 0x42)
|
|
elif letter == 'n':
|
|
scope = (0x43, 0x4B)
|
|
elif letter == 'o':
|
|
scope = (0x4C, 0x51)
|
|
elif letter == 'r':
|
|
scope = (0x54, 0x59)
|
|
elif letter == 's':
|
|
scope = (0x5A, 0x61)
|
|
elif letter == 't':
|
|
scope = (0x62, 0x67)
|
|
elif letter == 'u':
|
|
scope = (0x68, 0x73)
|
|
elif letter == 'w':
|
|
scope = (0x74, 0x75)
|
|
elif letter == 'y':
|
|
scope = (0x76, 0x77)
|
|
elif letter == 'z':
|
|
scope = (0x79, 0x7E)
|
|
|
|
if scope[0] < 0 or random() < unmangle_probability:
|
|
return letter_raw
|
|
|
|
new_int = randint(*scope)
|
|
if respect_case:
|
|
tmp_int = new_int - scope[0]
|
|
if letter_raw.isupper():
|
|
tmp_int &= 0xFFFE
|
|
else: # i.e. islower()
|
|
tmp_int |= 0x0001
|
|
new_int = tmp_int + scope[0]
|
|
else:
|
|
pass
|
|
|
|
# Now put it into the extended latin range
|
|
new_chr = chr(0x0100 | new_int)
|
|
return new_chr
|
|
|
|
# Pull a random list of diarac from the dirac table.
|
|
# https://en.wikipedia.org/wiki/Combining_character
|
|
def get_diracs(count) -> str:
|
|
diracs_list = []
|
|
for _ in range(count):
|
|
tmp_int = 0x4F
|
|
while tmp_int == 0x4F:
|
|
tmp_int = randint(0,0x6F)
|
|
diracs_list.append(chr(0x0300 | tmp_int))
|
|
return ''.join(diracs_list)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mangle() |