using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text.RegularExpressions; using System.Text; namespace Anyanka{ public class AnyankaKeys{ public static readonly char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".ToCharArray(); public static readonly byte[] PRIVATE_KEY = Enumerable.Range(0, 0x100).Select(i => (byte)i).ToArray(); const int MULTIPLIER = 1; const byte MULTIPLIER_JUMPS = 3; const byte MULTIPLIER_JUMP = 7; public static readonly uint[] PRIMES = new uint[]{ 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 }; public static readonly double LOGARITHM_256 = Math.Log(0x100); public static readonly Regex RE_KEY = new Regex(@"^[a-z_][a-z0-9_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled); public delegate byte ChangeBaseInputHandler(T value); public delegate void ChangeBaseOutputHandler(byte value); private char[] alphabet; private Dictionary dictionary; private byte[] private_key; private int multiplier; private byte multiplier_jumps; private byte multiplier_jump; private uint[] primes; private int _base; private int encrypt_i = 0; private byte[] password = new byte[]{0}; public AnyankaKeys(object? inputs = null){ alphabet = unique(get_array(get("alphabet", inputs, ALPHABET) ?? ALPHABET)); dictionary = new Dictionary(); private_key = get_numbers(get("private_key", inputs, PRIVATE_KEY) ?? PRIVATE_KEY); multiplier = get_number(get("multiplier", inputs, MULTIPLIER) ?? MULTIPLIER); multiplier_jumps = get_number(get("multiplier_jumps", inputs, MULTIPLIER_JUMPS) ?? MULTIPLIER_JUMPS); multiplier_jump = get_number(get("multiplier_jump", inputs, MULTIPLIER_JUMP) ?? MULTIPLIER_JUMP); primes = get_numbers(get("primes", inputs, PRIMES) ?? PRIMES); _base = get_number(get("base", inputs, alphabet.Length) ?? alphabet.Length); for(int i = 0; i < alphabet.Length; i++) dictionary[alphabet[i]] = i; set_password(get("password", inputs, "") ?? ""); if(_base < alphabet.Length) _base = alphabet.Length; } public void set_password(string password){ List changed = new List(); if(!string.IsNullOrEmpty(password)) change_base(password, _base, 0x100, (char value) => (byte)value, (byte value) => changed.Add(value)); if(changed.Count == 0) changed.Add(0); this.password = changed.ToArray(); } private uint get_multiplier(int i){ uint value = (uint)(i + multiplier + primes[ i = (i + multiplier_jump) % primes.Length ]) & 0x3FFFFFFF; for (int j = 0; j < multiplier_jumps; j++){ int shift = 13 + i % 8; value = ((value ^ ( (i & 1) == 1 ? value >> shift : value << shift )) + primes[ i = (i + multiplier_jump) % primes.Length ]) & 0x3FFFFFFF; } return value; } public string encrypt(string data){ int i = (int)(get_multiplier(encrypt_i + data.Length + (int)(DateTime.Now.Ticks % 1000)) % _base); string summatory = alphabet[i].ToString(); byte[] bytes = Encoding.UTF8.GetBytes(data); int j = (int)Math.Ceiling(bytes.Length * LOGARITHM_256 / Math.Log(_base)) + 2; char[] encrypted = new char[j]; encrypt_i = (encrypt_i + i) % _base; change_base(bytes, _base, 0x100, (byte value) => value, (byte value) => { uint multiplier = get_multiplier(i ++); encrypted[-- j] = alphabet[(multiplier + value + private_key[ multiplier / _base % private_key.Length ] + password[multiplier % password.Length]) % _base]; }); return summatory + new string(encrypted, j, encrypted.Length - j); } public string decrypt(string data){ int i = dictionary[data[0]] + data.Length - 1; int j = (int)Math.Ceiling(data.Length * Math.Log(_base) / LOGARITHM_256) + 2; byte[] decrypted = new byte[j]; change_base(data.Substring(1), 0x100, _base, (char value) => { uint multiplier = get_multiplier(-- i); return (byte)(((dictionary[value] - private_key[ multiplier / _base % private_key.Length ] - multiplier - password[multiplier % password.Length]) % _base + _base) % _base); }, (byte value) => { decrypted[-- j] = value; }); return Encoding.UTF8.GetString(decrypted, j, decrypted.Length - j); } public static List get_keys(object? items){ List keys = new List(); if(items is string item_string){ if(RE_KEY.IsMatch(item_string)) keys.Add(item_string); }else if(items is IEnumerable strings){ foreach(string item_i in strings) if(!keys.Contains(item_i) && RE_KEY.IsMatch(item_i)) keys.Add(item_i); }else if(items is IEnumerable list) foreach(object? item in list){ if(item == null) continue; if(item is string string_item){ if(!keys.Contains(string_item) && RE_KEY.IsMatch(string_item)) keys.Add(string_item); }else foreach(string key in get_keys(item)) if(!keys.Contains(key) && RE_KEY.IsMatch(key)) keys.Add(key); } return keys; } public static List> get_dictionaries(object? items){ List> dictionaries = new List>(); if(items is Dictionary dictionary) dictionaries.Add(dictionary); else if(items is IEnumerable list) foreach(object? item in list) dictionaries.AddRange(get_dictionaries(item)); return dictionaries; } public static T? get(object keys, object? dictionaries, T? _default = default(T?)){ List keys_list = get_keys(keys); if(keys_list.Count != 0) foreach(Dictionary dictionary in get_dictionaries(dictionaries)) foreach(string key in keys_list) if(dictionary.TryGetValue(key, out object? value) && value is T typed) return typed; return _default; } public static T[] unique(IEnumerable items){ return items.Distinct().ToArray(); } public static void change_base( IEnumerable data, int to_base, int from_base = 0x100, ChangeBaseInputHandler? input_handler = null, ChangeBaseOutputHandler? output_handler = null ){ int stack = 0; bool has = false; if(input_handler == null) input_handler = (T value) => Convert.ToByte(value); if(output_handler == null) output_handler = (byte value) => { }; foreach(T value in data){ stack = stack * from_base + input_handler(value); while(stack >= to_base){ has = true; output_handler((byte)(stack % to_base)); stack /= to_base; } } if(!has || stack != 0) output_handler((byte)stack); } public static T[] get_array(object data){ if(data is T item_t) return new T[]{item_t}; if(data is string text && typeof(T) == typeof(char)) return text.ToCharArray() as T[] ?? new T[]{}; if(data is IEnumerable list_t) return list_t.ToArray(); if(data is IEnumerable list){ List results = new List(); foreach(object? item in list) if(item is T typed) results.Add(typed); return results.ToArray(); } return new T[]{}; } public static T get_number(object data){ if(data is T item) return item; return (T)Convert.ChangeType(data, typeof(T)); } public static T[] get_numbers(object data){ if(data is T item_t) return new T[]{item_t}; if(data is T[] item_set) return item_set; if(data is IEnumerable list){ List results = new List(); foreach(object? item in list) if(item != null) results.Add(get_number(item)); return results.ToArray(); } return new T[]{}; } } }