205 lines
7.1 KiB
Python
205 lines
7.1 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from typing import Any, Self, Callable, Optional, TypeVar, Iterable
|
|
from time import time
|
|
from re import compile as re_compile, Pattern as RePattern, I as RE_IgnoreCase
|
|
|
|
T = TypeVar("T", int, float, str, bytes)
|
|
|
|
class AnyankaKeys:
|
|
|
|
__slots__:tuple[str] = (
|
|
'__alphabet', '__dictionary', '__private_key', '__private_key_l',
|
|
'__multiplier', '__primes', '__primes_l', '__multiplier_jumps',
|
|
'__multiplier_jump', '__base', '__encrypt_i', '__password', '__password_l'
|
|
)
|
|
|
|
ALPHABET:tuple[str] = tuple("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
|
PRIVATE_KEY:tuple[int] = tuple(range(1, 0x100))
|
|
MULTIPLIER:int = 1
|
|
MULTIPLIER_JUMPS:int = 3
|
|
MULTIPLIER_JUMP:int = 7
|
|
PRIMES:tuple[int] = (
|
|
0x3FFFFFFB, 0x3FFFFF29, 0x3FFFFF0B,
|
|
0x2FFFFFFF, 0x2FFFFF5B, 0x1FFFFFFF,
|
|
0x279DB13D, 0x279DB113,
|
|
0x2AAAAAAB, 0x1555556B, 0x27D4EB2F, 0x165667B1,
|
|
0x1000007F, 0x3B9ACA07, 0x01000193, 0x1EADBEEF, 0x0AFEBABE, 0x0BADC0DE, 0x3B9AC9C1, 0x1D295C4D, 0x990BF9F, 0x1CFAA2DB,
|
|
0xDEADBEEF, 0xCAFEBABF, 0xBAADF00D
|
|
)
|
|
|
|
RE_KEY:RePattern = re_compile(r'^[a-z_][a-z0-9_]*$', RE_IgnoreCase)
|
|
|
|
def __init__(self:Self, inputs:Optional[dict[str, Any|None]] = None) -> None:
|
|
|
|
self.__alphabet:tuple[str] = tuple(self.unique(self.get_value("alphabet", inputs, self.ALPHABET)))
|
|
self.__dictionary:dict[str, int] = {value : index for index, value in enumerate(self.__alphabet)}
|
|
self.__private_key:tuple[int] = tuple(self.get_value("private_key", inputs, self.PRIVATE_KEY))
|
|
self.__private_key_l:int = len(self.__private_key)
|
|
self.__multiplier:int = self.get_value("multiplier", inputs, self.MULTIPLIER)
|
|
self.__primes:tuple[int] = tuple(self.get_value("primes", inputs, self.PRIMES))
|
|
self.__primes_l:int = len(self.__primes)
|
|
self.__multiplier_jumps:int = self.get_value("multiplier_jumps", inputs, self.MULTIPLIER_JUMPS)
|
|
self.__multiplier_jump:int = self.get_value("multiplier_jump", inputs, self.MULTIPLIER_JUMP)
|
|
l:int = len(self.__alphabet)
|
|
self.__base:int = self.get_value("base", inputs, l)
|
|
self.__encrypt_i:int = 0
|
|
self.__password:tuple[int] = (0,)
|
|
self.__password_l:int = 1
|
|
|
|
self.set_password(self.get_value("password", inputs, ""))
|
|
|
|
if self.__base > l:
|
|
self.__base = l
|
|
|
|
def set_password(self:Self, password:str) -> None:
|
|
|
|
if password:
|
|
|
|
password_changed:list[int] = []
|
|
|
|
self.change_base(password, self.__base, input_handler = ord, output_handler = password_changed.append)
|
|
self.__password = tuple(password_changed)
|
|
|
|
else:
|
|
self.__password = (0,)
|
|
|
|
self.__password_l = len(self.__password)
|
|
|
|
def __get_multiplier(self:Self, i:int) -> int:
|
|
|
|
value:int = (i + self.__multiplier + self.__primes[
|
|
i := (i + self.__multiplier_jump) % self.__primes_l
|
|
]) & 0x3FFFFFFF
|
|
|
|
for _ in range(self.__multiplier_jumps):
|
|
|
|
shift:int = 13 + i % 8
|
|
|
|
value = ((value ^ (
|
|
value >> shift if i & 1 else value << shift
|
|
)) + self.__primes[
|
|
i := (i + self.__multiplier_jump) % self.__primes_l
|
|
]) & 0x3FFFFFFF
|
|
|
|
return value
|
|
|
|
def encrypt(self:Self, data:str) -> str:
|
|
|
|
i:int = self.__get_multiplier(self.__encrypt_i + len(data) + int(time() % 1 * 1000)) % self.__base
|
|
summatory:str = self.__alphabet[i]
|
|
encrypted:list[str] = []
|
|
|
|
self.__encrypt_i += i
|
|
i -= 1
|
|
|
|
def output_handler(value:int) -> None:
|
|
nonlocal encrypted, i
|
|
|
|
multiplier:int = self.__get_multiplier(i := i + 1)
|
|
|
|
encrypted.append(self.__alphabet[(multiplier + value + self.__private_key[
|
|
multiplier // self.__base % self.__private_key_l
|
|
] + self.__password[multiplier % self.__password_l]) % self.__base])
|
|
|
|
self.change_base(data, self.__base, 0x100,
|
|
input_handler = ord,
|
|
output_handler = output_handler
|
|
)
|
|
|
|
return summatory + "".join(reversed(encrypted))
|
|
|
|
def decrypt(self:Self, data:str) -> str:
|
|
|
|
i:int = len(data[1:]) + self.__dictionary[data[0]]
|
|
decrypted:list[str] = []
|
|
|
|
def output_handler(value:int) -> None:
|
|
nonlocal decrypted
|
|
decrypted.append(chr(value))
|
|
|
|
def input_handler(value:str) -> int:
|
|
nonlocal i
|
|
|
|
multiplier:int = self.__get_multiplier(i := i - 1)
|
|
|
|
return (self.__dictionary[value] - self.__private_key[
|
|
multiplier // self.__base % self.__private_key_l
|
|
] - multiplier - self.__password[multiplier % self.__password_l]) % self.__base
|
|
|
|
self.change_base(data[1:], 0x100, self.__base,
|
|
input_handler = input_handler,
|
|
output_handler = output_handler
|
|
)
|
|
|
|
return "".join(reversed(decrypted))
|
|
|
|
@classmethod
|
|
def get_keys(cls:type[Self], *inputs:Iterable[Any|None]) -> list[str]:
|
|
|
|
keys:list[str] = []
|
|
|
|
for item in inputs:
|
|
if isinstance(item, str):
|
|
cls.RE_KEY.match(item) and item in keys or keys.append(item)
|
|
elif isinstance(item, (list, tuple)):
|
|
keys.extend(cls.get_keys(*item))
|
|
|
|
return keys
|
|
|
|
@classmethod
|
|
def get_dictionaries(cls:type[Self], *inputs:Iterable[Any|None]) -> list[dict[str, Any|None]]:
|
|
|
|
dictionaries:list[dict[str, Any|None]] = []
|
|
|
|
for item in inputs:
|
|
if isinstance(item, dict):
|
|
dictionaries.append(item)
|
|
elif isinstance(item, (list, tuple)):
|
|
dictionaries.extend(cls.get_dictionaries(*item))
|
|
|
|
return dictionaries
|
|
|
|
@classmethod
|
|
def get_value(
|
|
cls:type[Self],
|
|
keys:str|list[str]|tuple[str, ...],
|
|
inputs:dict[str, Any|None]|Iterable[Any|None],
|
|
default:Optional[Any] = None
|
|
) -> Any|None:
|
|
if len(keys := cls.get_keys(keys)):
|
|
for dictionary in cls.get_dictionaries(inputs):
|
|
for key in keys:
|
|
if key in dictionary:
|
|
return dictionary[key]
|
|
return default
|
|
|
|
@staticmethod
|
|
def unique(items:Iterable[Any|None]) -> list[Any|None]:
|
|
return list(dict.fromkeys(items))
|
|
|
|
@staticmethod
|
|
def change_base(
|
|
data:Iterable[T],
|
|
to_base:int,
|
|
from_base:int = 0x100,
|
|
input_handler:Optional[Callable[[T], int]] = None,
|
|
output_handler:Optional[Callable[[int], None]] = None
|
|
) -> None:
|
|
|
|
stack:int = 0
|
|
value:int
|
|
has:bool = False
|
|
|
|
if input_handler is None:input_handler = lambda value:value
|
|
if output_handler is None:output_handler = lambda value:value
|
|
|
|
for value in data:
|
|
stack = stack * from_base + input_handler(value)
|
|
while stack >= to_base:
|
|
has = True
|
|
stack, value = divmod(stack, to_base)
|
|
output_handler(value)
|
|
|
|
(not has or stack) and output_handler(stack) |