271 lines
10 KiB
C#
271 lines
10 KiB
C#
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<int, byte>(i => (byte)i).ToArray<byte>();
|
|
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>(T value);
|
|
public delegate void ChangeBaseOutputHandler(byte value);
|
|
|
|
private char[] alphabet;
|
|
private Dictionary<char, int> 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<char>(get_array<char>(get<object>("alphabet", inputs, ALPHABET) ?? ALPHABET));
|
|
dictionary = new Dictionary<char, int>();
|
|
private_key = get_numbers<byte>(get<object>("private_key", inputs, PRIVATE_KEY) ?? PRIVATE_KEY);
|
|
multiplier = get_number<int>(get<object>("multiplier", inputs, MULTIPLIER) ?? MULTIPLIER);
|
|
multiplier_jumps = get_number<byte>(get<object>("multiplier_jumps", inputs, MULTIPLIER_JUMPS) ?? MULTIPLIER_JUMPS);
|
|
multiplier_jump = get_number<byte>(get<object>("multiplier_jump", inputs, MULTIPLIER_JUMP) ?? MULTIPLIER_JUMP);
|
|
primes = get_numbers<uint>(get<object>("primes", inputs, PRIMES) ?? PRIMES);
|
|
_base = get_number<int>(get<object>("base", inputs, alphabet.Length) ?? alphabet.Length);
|
|
|
|
for(int i = 0; i < alphabet.Length; i++)
|
|
dictionary[alphabet[i]] = i;
|
|
|
|
set_password(get<string>("password", inputs, "") ?? "");
|
|
|
|
if(_base < alphabet.Length)
|
|
_base = alphabet.Length;
|
|
|
|
}
|
|
|
|
public void set_password(string password){
|
|
|
|
List<byte> changed = new List<byte>();
|
|
|
|
if(!string.IsNullOrEmpty(password))
|
|
change_base<char>(password, _base, 0x100, (char value) => (byte)value, (byte value) => changed.Add(value));
|
|
|
|
if(changed.Count == 0)
|
|
changed.Add(0);
|
|
|
|
this.password = changed.ToArray<byte>();
|
|
|
|
}
|
|
|
|
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<byte>(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<char>(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<string> get_keys(object? items){
|
|
|
|
List<string> keys = new List<string>();
|
|
|
|
if(items is string item_string){
|
|
if(RE_KEY.IsMatch(item_string))
|
|
keys.Add(item_string);
|
|
}else if(items is IEnumerable<string> 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<object?> 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<Dictionary<string, object?>> get_dictionaries(object? items){
|
|
|
|
List<Dictionary<string, object?>> dictionaries = new List<Dictionary<string, object?>>();
|
|
|
|
if(items is Dictionary<string, object?> dictionary)
|
|
dictionaries.Add(dictionary);
|
|
else if(items is IEnumerable<object?> list)
|
|
foreach(object? item in list)
|
|
dictionaries.AddRange(get_dictionaries(item));
|
|
|
|
return dictionaries;
|
|
}
|
|
|
|
public static T? get<T>(object keys, object? dictionaries, T? _default = default(T?)){
|
|
|
|
List<string> keys_list = get_keys(keys);
|
|
|
|
if(keys_list.Count != 0)
|
|
foreach(Dictionary<string, object?> 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<T>(IEnumerable<T> items){
|
|
return items.Distinct<T>().ToArray<T>();
|
|
}
|
|
|
|
public static void change_base<T>(
|
|
IEnumerable<T> data,
|
|
int to_base,
|
|
int from_base = 0x100,
|
|
ChangeBaseInputHandler<T>? 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<T>(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<T> list_t)
|
|
return list_t.ToArray();
|
|
if(data is IEnumerable list){
|
|
|
|
List<T> results = new List<T>();
|
|
|
|
foreach(object? item in list)
|
|
if(item is T typed)
|
|
results.Add(typed);
|
|
|
|
return results.ToArray();
|
|
}
|
|
return new T[]{};
|
|
}
|
|
|
|
public static T get_number<T>(object data){
|
|
if(data is T item)
|
|
return item;
|
|
return (T)Convert.ChangeType(data, typeof(T));
|
|
}
|
|
|
|
public static T[] get_numbers<T>(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<T> results = new List<T>();
|
|
|
|
foreach(object? item in list)
|
|
if(item != null)
|
|
results.Add(get_number<T>(item));
|
|
|
|
return results.ToArray();
|
|
}
|
|
return new T[]{};
|
|
}
|
|
|
|
}
|
|
} |