diff --git a/Console/App.config b/Console/App.config index 56efbc7..4bfa005 100644 --- a/Console/App.config +++ b/Console/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/Console/Ed25519.cs b/Console/Ed25519.cs new file mode 100644 index 0000000..20d1480 --- /dev/null +++ b/Console/Ed25519.cs @@ -0,0 +1,322 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Security.Cryptography; + +namespace Cryptographic +{ + /* Ported and refactored from Java to C# by Hans Wolff, 10/10/2013 + * Released to the public domain + * / + + /* Java code written by k3d3 + * Source: https://github.com/k3d3/ed25519-java/blob/master/ed25519.java + * Released to the public domain + */ + + public class Ed25519 + { + private static byte[] ComputeHash(byte[] m) + { + using (var sha512 = SHA512.Create()) // System.Security.Cryptography + { + return sha512.ComputeHash(m); + } + } + + private static BigInteger ExpMod(BigInteger number, BigInteger exponent, BigInteger modulo) + { + BigInteger result = BigInteger.One; + BigInteger baseVal = number.Mod(modulo); + + while (exponent > 0) + { + if (!exponent.IsEven) + { + result = (result * baseVal).Mod(modulo); + } + baseVal = (baseVal * baseVal).Mod(modulo); + exponent /= 2; + } + + return result; + } + + + private static readonly Dictionary InverseCache = new Dictionary(); + + private static BigInteger Inv(BigInteger x) + { + if (!InverseCache.ContainsKey(x)) + { + InverseCache[x] = ExpMod(x, Qm2, Q); + } + return InverseCache[x]; + } + + private static BigInteger RecoverX(BigInteger y) + { + BigInteger y2 = y * y; + BigInteger xx = (y2 - 1) * Inv(D * y2 + 1); + BigInteger x = ExpMod(xx, Qp3 / Eight, Q); + if (!(x * x - xx).Mod(Q).Equals(BigInteger.Zero)) + { + x = (x * I).Mod(Q); + } + if (!x.IsEven) + { + x = Q - x; + } + return x; + } + + private static Tuple Edwards(BigInteger px, BigInteger py, BigInteger qx, BigInteger qy) + { + BigInteger xx12 = px * qx; + BigInteger yy12 = py * qy; + BigInteger dtemp = D * xx12 * yy12; + BigInteger x3 = (px * qy + qx * py) * (Inv(1 + dtemp)); + BigInteger y3 = (py * qy + xx12) * (Inv(1 - dtemp)); + return new Tuple(x3.Mod(Q), y3.Mod(Q)); + } + + private static Tuple EdwardsSquare(BigInteger x, BigInteger y) + { + BigInteger xx = x * x; + BigInteger yy = y * y; + BigInteger dtemp = D * xx * yy; + BigInteger x3 = (2 * x * y) * (Inv(1 + dtemp)); + BigInteger y3 = (yy + xx) * (Inv(1 - dtemp)); + return new Tuple(x3.Mod(Q), y3.Mod(Q)); + } + private static Tuple ScalarMul(Tuple point, BigInteger scalar) + { + var result = new Tuple(BigInteger.Zero, BigInteger.One); // Neutral element + var basePoint = point; + + while (scalar > 0) + { + if (!scalar.IsEven) // If the current bit is set, add the base point to the result + { + result = Edwards(result.Item1, result.Item2, basePoint.Item1, basePoint.Item2); + } + + basePoint = EdwardsSquare(basePoint.Item1, basePoint.Item2); // Double the point + scalar >>= 1; // Move to the next bit in the scalar + } + + return result; + } + + public static byte[] EncodeInt(BigInteger y) + { + byte[] nin = y.ToByteArray(); + var nout = new byte[Math.Max(nin.Length, 32)]; + Array.Copy(nin, nout, nin.Length); + return nout; + } + + public static byte[] EncodePoint(BigInteger x, BigInteger y) + { + byte[] nout = EncodeInt(y); + nout[nout.Length - 1] |= (x.IsEven ? (byte)0 : (byte)0x80); + return nout; + } + + private static int GetBit(byte[] h, int i) + { + return h[i / 8] >> (i % 8) & 1; + } + + public static byte[] PublicKey(byte[] signingKey) + { + byte[] h = ComputeHash(signingKey); + BigInteger a = TwoPowBitLengthMinusTwo; + for (int i = 3; i < (BitLength - 2); i++) + { + var bit = GetBit(h, i); + if (bit != 0) + { + a += TwoPowCache[i]; + } + } + var bigA = ScalarMul(B, a); + return EncodePoint(bigA.Item1, bigA.Item2); + } + + private static BigInteger HashInt(byte[] m) + { + byte[] h = ComputeHash(m); + BigInteger hsum = BigInteger.Zero; + for (int i = 0; i < 2 * BitLength; i++) + { + var bit = GetBit(h, i); + if (bit != 0) + { + hsum += TwoPowCache[i]; + } + } + return hsum; + } + + public static byte[] Signature(byte[] message, byte[] signingKey, byte[] publicKey) + { + byte[] h = ComputeHash(signingKey); + BigInteger a = TwoPowBitLengthMinusTwo; + for (int i = 3; i < (BitLength - 2); i++) + { + var bit = GetBit(h, i); + if (bit != 0) + { + a += TwoPowCache[i]; + } + } + + BigInteger r; + using (var rsub = new MemoryStream((BitLength / 8) + message.Length)) + { + rsub.Write(h, BitLength / 8, BitLength / 4 - BitLength / 8); + rsub.Write(message, 0, message.Length); + r = HashInt(rsub.ToArray()); + } + var bigR = ScalarMul(B, r); + BigInteger s; + var encodedBigR = EncodePoint(bigR.Item1, bigR.Item2); + using (var stemp = new MemoryStream(32 + publicKey.Length + message.Length)) + { + stemp.Write(encodedBigR, 0, encodedBigR.Length); + stemp.Write(publicKey, 0, publicKey.Length); + stemp.Write(message, 0, message.Length); + s = (r+ HashInt(stemp.ToArray()) * a).Mod(L); + } + + using (var nout = new MemoryStream(64)) + { + nout.Write(encodedBigR, 0, encodedBigR.Length); + var encodeInt = EncodeInt(s); + nout.Write(encodeInt, 0, encodeInt.Length); + return nout.ToArray(); + } + } + + private static bool IsOnCurve(BigInteger x, BigInteger y) + { + BigInteger xx = x * x; + BigInteger yy = y * y; + BigInteger dxxyy = D * yy * xx; + return (yy - xx - dxxyy - 1).Mod(Q).Equals(BigInteger.Zero); + } + + private static BigInteger DecodeInt(byte[] s) + { + return new BigInteger(s) & Un; + } + + private static Tuple DecodePoint(byte[] pointBytes) + { + BigInteger y = new BigInteger(pointBytes) & Un; + BigInteger x = RecoverX(y); + if ((x.IsEven ? 0 : 1) != GetBit(pointBytes, BitLength - 1)) + { + x = Q - x; + } + var point = new Tuple(x, y); + if (!IsOnCurve(x, y)) throw new ArgumentException("Decoding point that is not on curve"); + return point; + } + + public static bool CheckValid(byte[] signature, byte[] message, byte[] publicKey) + { + Console.Write("."); // ... dots in console + if (signature.Length != BitLength / 4) throw new ArgumentException("Signature length is wrong"); + if (publicKey.Length != BitLength / 8) throw new ArgumentException("Public key length is wrong"); + + byte[] rByte = Arrays.CopyOfRange(signature, 0, BitLength / 8); + + var r = DecodePoint(rByte); + var a = DecodePoint(publicKey); + + byte[] sByte = Arrays.CopyOfRange(signature, BitLength / 8, BitLength / 4); + + BigInteger s = DecodeInt(sByte); + BigInteger h; + + using (var stemp = new MemoryStream(32 + publicKey.Length + message.Length)) + { + var encodePoint = EncodePoint(r.Item1, r.Item2); + stemp.Write(encodePoint, 0, encodePoint.Length); + stemp.Write(publicKey, 0, publicKey.Length); + stemp.Write(message, 0, message.Length); + h = HashInt(stemp.ToArray()); + } + + Console.Write("."); // ... dots in console + var ra = ScalarMul(B, s); + Console.Write("."); // ... dots in console + var ah = ScalarMul(a, h); + var rb = Edwards(r.Item1, r.Item2, ah.Item1, ah.Item2); + if (!ra.Item1.Equals(rb.Item1) || !ra.Item2.Equals(rb.Item2)) + return false; + return true; + } + + private const int BitLength = 256; + + private static readonly BigInteger TwoPowBitLengthMinusTwo = BigInteger.Pow(2, BitLength - 2); + private static readonly BigInteger[] TwoPowCache = Enumerable.Range(0, 2 * BitLength).Select(i => BigInteger.Pow(2, i)).ToArray(); + + private static readonly BigInteger Q = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819949"); + + private static readonly BigInteger Qm2 = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819947"); + + private static readonly BigInteger Qp3 = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819952"); + + private static readonly BigInteger L = + BigInteger.Parse("7237005577332262213973186563042994240857116359379907606001950938285454250989"); + + private static readonly BigInteger D = + BigInteger.Parse("-4513249062541557337682894930092624173785641285191125241628941591882900924598840740"); + + private static readonly BigInteger I = + BigInteger.Parse("19681161376707505956807079304988542015446066515923890162744021073123829784752"); + + private static readonly BigInteger By = + BigInteger.Parse("46316835694926478169428394003475163141307993866256225615783033603165251855960"); + + private static readonly BigInteger Bx = + BigInteger.Parse("15112221349535400772501151409588531511454012693041857206046113283949847762202"); + + private static readonly Tuple B = new Tuple(Bx.Mod(Q), By.Mod(Q)); + + private static readonly BigInteger Un = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819967"); + + private static readonly BigInteger Two = new BigInteger(2); + private static readonly BigInteger Eight = new BigInteger(8); + } + + internal static class Arrays + { + public static byte[] CopyOfRange(byte[] original, int from, int to) + { + int length = to - from; + var result = new byte[length]; + Array.Copy(original, from, result, 0, length); + return result; + } + } + + internal static class BigIntegerHelpers + { + public static BigInteger Mod(this BigInteger num, BigInteger modulo) + { + var result = num % modulo; + return result < 0 ? result + modulo : result; + } + } +} \ No newline at end of file diff --git a/Console/KeyAuth.cs b/Console/KeyAuth.cs index 5044222..88f39f4 100644 --- a/Console/KeyAuth.cs +++ b/Console/KeyAuth.cs @@ -12,41 +12,51 @@ using System.Security.Cryptography.X509Certificates; using System.Net.Security; using System.Threading; -using System.Runtime.CompilerServices; +using Cryptographic; +using System.Runtime.InteropServices; namespace KeyAuth { public class api { - public string name, ownerid, secret, version, path; - public static long responseTime; + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetCurrentProcess(); + + // Import the required Atom Table functions from kernel32.dll + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern ushort GlobalAddAtom(string lpString); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern ushort GlobalFindAtom(string lpString); + + public string name, ownerid, version, path, seed; /// /// Set up your application credentials in order to use keyauth /// /// Application Name /// Your OwnerID, found in your account settings. - /// Application Secret /// Application Version, if version doesnt match it will open the download link you set up in your application settings and close the app, if empty the app will close - public api(string name, string ownerid, string secret, string version, string path = null) + public api(string name, string ownerid, string version, string path = null) { - if (ownerid.Length != 10 || secret.Length != 64) + if (ownerid.Length != 10) { Process.Start("https://youtube.com/watch?v=RfDTdiBq4_o"); Process.Start("https://keyauth.cc/app/"); Thread.Sleep(2000); error("Application not setup correctly. Please watch the YouTube video for setup."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } this.name = name; this.ownerid = ownerid; - this.secret = secret; - this.version = version; - this.path = path; + this.path = path; } #region structures @@ -71,6 +81,9 @@ private class response_structure [DataMember] public string message { get; set; } + [DataMember] + public string ownerid { get; set; } + [DataMember] public string download { get; set; } @@ -141,20 +154,35 @@ private class app_data_structure /// public void init() { - string sentKey = encryption.iv_key(); - enckey = sentKey + "-" + secret; + Random random = new Random(); + + // Generate a random length for the string (let's assume between 5 and 50 characters) + int length = random.Next(5, 51); // Min length: 5, Max length: 50 + + StringBuilder sb = new StringBuilder(length); + + // Define the range of printable ASCII characters (32-126) + for (int i = 0; i < length; i++) + { + // Generate a random printable ASCII character + char randomChar = (char)random.Next(32, 127); // ASCII 32 to 126 + sb.Append(randomChar); + } + + seed = sb.ToString(); + checkAtom(); + var values_to_upload = new NameValueCollection { ["type"] = "init", ["ver"] = version, ["hash"] = checksum(Process.GetCurrentProcess().MainModule.FileName), - ["enckey"] = sentKey, ["name"] = name, ["ownerid"] = ownerid }; - if (!string.IsNullOrEmpty(path)) - { + if (!string.IsNullOrEmpty(path)) + { values_to_upload.Add("token", File.ReadAllText(path)); values_to_upload.Add("thash", TokenHash(path)); } @@ -164,28 +192,50 @@ public void init() if (response == "KeyAuth_Invalid") { error("Application not found"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) + if (json.ownerid == ownerid) { - if(json.newSession) + load_response_struct(json); + if (json.success) + { + sessionid = json.sessionid; + initialized = true; + } + else if (json.message == "invalidver") { - Thread.Sleep(100); + app_data.downloadLink = json.download; } - sessionid = json.sessionid; - initialized = true; } - else if (json.message == "invalidver") + else { - app_data.downloadLink = json.download; + TerminateProcess(GetCurrentProcess(), 1); } + } + + void checkAtom() + { + Thread atomCheckThread = new Thread(() => + { + while (true) + { + Thread.Sleep(60000); // give people 1 minute to login + ushort foundAtom = GlobalFindAtom(seed); + if (foundAtom == 0) + { + TerminateProcess(GetCurrentProcess(), 1); + } + } + }); + + atomCheckThread.IsBackground = true; // Ensure the thread does not block program exit + atomCheckThread.Start(); } - public static string TokenHash(string tokenPath) + public static string TokenHash(string tokenPath) { using (var sha256 = SHA256.Create()) { @@ -204,7 +254,7 @@ public void CheckInit() if (!initialized) { error("You must run the function KeyAuthApp.init(); first"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } } @@ -261,9 +311,19 @@ public void register(string username, string pass, string key, string email = "" var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - load_user_data(json.info); + if (json.ownerid == ownerid) + { + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + if (json.success) + load_user_data(json.info); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Allow users to enter their account information and recieve an email to reset their password. @@ -314,9 +374,19 @@ public void login(string username, string pass) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - load_user_data(json.info); + if (json.ownerid == ownerid) + { + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + if (json.success) + load_user_data(json.info); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } public void logout() @@ -334,7 +404,14 @@ public void logout() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } public void web_login() @@ -403,26 +480,35 @@ public void web_login() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - bool success = true; - - if (json.success) + if (json.ownerid == ownerid) { - load_user_data(json.info); + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + + if (json.success) + { + load_user_data(json.info); - responsepp.StatusCode = 420; - responsepp.StatusDescription = "SHEESH"; + responsepp.StatusCode = 420; + responsepp.StatusDescription = "SHEESH"; + } + else + { + Console.WriteLine(json.message); + responsepp.StatusCode = (int)HttpStatusCode.OK; + responsepp.StatusDescription = json.message; + success = false; + } } else { - Console.WriteLine(json.message); - responsepp.StatusCode = (int)HttpStatusCode.OK; - responsepp.StatusDescription = json.message; - success = false; + TerminateProcess(GetCurrentProcess(), 1); } - byte[] buffer = Encoding.UTF8.GetBytes("Whats up?"); + byte[] buffer = Encoding.UTF8.GetBytes("Complete"); responsepp.ContentLength64 = buffer.Length; Stream output = responsepp.OutputStream; @@ -431,7 +517,7 @@ public void web_login() listener.Stop(); if (!success) - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } @@ -498,8 +584,15 @@ public void upgrade(string username, string key) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - json.success = false; - load_response_struct(json); + if (json.ownerid == ownerid) + { + json.success = false; + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// @@ -525,9 +618,20 @@ public void license(string key) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - load_user_data(json.info); + + if (json.ownerid == ownerid) + { + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + if (json.success) + load_user_data(json.info); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Checks if the current session is validated or not @@ -547,7 +651,14 @@ public void check() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Change the data of an existing user variable, *User must be logged in* @@ -571,7 +682,14 @@ public void setvar(string var, string data) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Gets the an existing user variable @@ -594,9 +712,16 @@ public string getvar(string var) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return json.response; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return json.response; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } return null; } /// @@ -618,7 +743,14 @@ public void ban(string reason = null) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Gets an existing global variable @@ -641,9 +773,16 @@ public string var(string varid) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return json.message; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return json.message; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } return null; } /// @@ -771,10 +910,19 @@ public bool checkblack() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return true; - return false; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return true; + else + return false; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } + return true; // return yes blacklisted if the OwnerID is spoofed } /// /// Sends a request to a webhook that you've added in the dashboard in a safe way without it being showed for example a http debugger @@ -803,9 +951,16 @@ public string webhook(string webid, string param, string body = "", string contt var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return json.response; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return json.response; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } return null; } /// @@ -911,7 +1066,6 @@ public static void LogEvent(string content) content = RedactField(content, "sessionid"); content = RedactField(content, "ownerid"); content = RedactField(content, "app"); - content = RedactField(content, "secret"); content = RedactField(content, "version"); content = RedactField(content, "fileid"); content = RedactField(content, "webhooks"); @@ -963,7 +1117,7 @@ public static void error(string message) RedirectStandardError = true, UseShellExecute = false }); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } private static string req(NameValueCollection post_data) @@ -976,17 +1130,11 @@ private static string req(NameValueCollection post_data) ServicePointManager.ServerCertificateValidationCallback += assertSSL; - Stopwatch stopwatch = new Stopwatch(); - stopwatch.Start(); - - var raw_response = client.UploadValues("https://keyauth.win/api/1.2/", post_data); - - stopwatch.Stop(); - responseTime = stopwatch.ElapsedMilliseconds; + var raw_response = client.UploadValues("https://keyauth.win/api/1.3/", post_data); ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; - sigCheck(Encoding.UTF8.GetString(raw_response), client.ResponseHeaders["signature"], post_data.Get(0)); + sigCheck(Encoding.UTF8.GetString(raw_response), client.ResponseHeaders, post_data.Get(0)); LogEvent(Encoding.Default.GetString(raw_response) + "\n"); @@ -1001,12 +1149,12 @@ private static string req(NameValueCollection post_data) case (HttpStatusCode)429: // client hit our rate limit error("You're connecting too fast to loader, slow down."); LogEvent("You're connecting too fast to loader, slow down."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); return ""; default: // site won't resolve. you should use keyauth.uk domain since it's not blocked by any ISPs error("Connection failure. Please try again, or contact us for help."); LogEvent("Connection failure. Please try again, or contact us for help."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); return ""; } } @@ -1023,28 +1171,61 @@ private static bool assertSSL(object sender, X509Certificate certificate, X509Ch return true; } - private static void sigCheck(string resp, string signature, string type) + private static void sigCheck(string resp, WebHeaderCollection headers, string type) { if(type == "log" || type == "file") // log doesn't return a response. { return; } - + try { - string clientComputed = encryption.HashHMAC((type == "init") ? enckey.Substring(17, 64) : enckey, resp); - if (!encryption.CheckStringsFixedTime(clientComputed, signature)) + string signature = headers["x-signature-ed25519"]; + string timestamp = headers["x-signature-timestamp"]; + + // Try to parse the input string to a long Unix timestamp + if (!long.TryParse(timestamp, out long unixTimestamp)) + { + TerminateProcess(GetCurrentProcess(), 1); + } + + // Convert the Unix timestamp to a DateTime object (in UTC) + DateTime timestampTime = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp).UtcDateTime; + + // Get the current UTC time + DateTime currentTime = DateTime.UtcNow; + + // Calculate the difference between the current time and the timestamp + TimeSpan timeDifference = currentTime - timestampTime; + + // Check if the timestamp is within 15 seconds of the current time + if (timeDifference.TotalSeconds > 15) + { + TerminateProcess(GetCurrentProcess(), 1); + } + + var byteSig = encryption.str_to_byte_arr(signature); + var byteKey = encryption.str_to_byte_arr("5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b"); + // ... read the body from the request ... + // ... add the timestamp and convert it to a byte[] ... + string body = timestamp + resp; + var byteBody = Encoding.Default.GetBytes(body); + + Console.Write(" Authenticating"); // there's also ... dots being created inside the CheckValid() function BELOW + + bool signatureValid = Ed25519.CheckValid(byteSig, byteBody, byteKey); // the ... dots in the console are from this function! + if (!signatureValid) { error("Signature checksum failed. Request was tampered with or session ended most likely. & echo: & echo Response: " + resp); LogEvent(resp + "\n"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } } catch { error("Signature checksum failed. Request was tampered with or session ended most likely. & echo: & echo Response: " + resp); LogEvent(resp + "\n"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } } @@ -1122,6 +1303,12 @@ private void load_response_struct(response_structure data) public static class encryption { + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetCurrentProcess(); + public static string HashHMAC(string enckey, string resp) { byte[] key = Encoding.UTF8.GetBytes(enckey); @@ -1151,25 +1338,10 @@ public static byte[] str_to_byte_arr(string hex) catch { api.error("The session has ended, open program again."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); return null; } } - - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] - public static bool CheckStringsFixedTime(string str1, string str2) - { - if (str1.Length != str2.Length) - { - return false; - } - var result = 0; - for (var i = 0; i < str1.Length; i++) - { - result |= str1[i] ^ str2[i]; - } - return result == 0; - } public static string iv_key() => Guid.NewGuid().ToString().Substring(0, 16); diff --git a/Console/Loader.csproj b/Console/Loader.csproj index ca6625c..d5b83a1 100644 --- a/Console/Loader.csproj +++ b/Console/Loader.csproj @@ -8,7 +8,7 @@ Exe Loader Loader - v4.7.2 + v4.8 512 true true @@ -27,6 +27,7 @@ false false true + AnyCPU @@ -54,11 +55,13 @@ + + diff --git a/Console/Program.cs b/Console/Program.cs index 5570eae..2014845 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -1,6 +1,11 @@ using System; using System.Diagnostics; +using System.Linq; using System.Net; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; using System.Threading; using System.Windows.Forms; @@ -18,22 +23,26 @@ class Program */ public static api KeyAuthApp = new api( - name: "", - ownerid: "", - secret: "", - version: "1.0"/*, - path: @"PathToCheckToken" NOTE: THE "@" IS IF THE TOKEN.TXT FILE IS IN THE SAME DIRECTORY AS THE .EXE*/ + name: "", // Application Name + ownerid: "", // Owner ID + version: "" // Application Version /* + //path: @"Your_Path_Here" // (OPTIONAL) see tutorial here https://www.youtube.com/watch?v=I9rxt821gMk&t=1s ); - // This will display how long it took to make a request in ms. The param "type" is for "login", "register", "init", etc... but that is optional, as well as this function. Ideally you can just put Console.WriteLine($"Request took {api.responseTime}"), but either works. - // if you would like to use this method, simply put it in any function and pass the param ... ShowResponse("TypeHere"); - private void ShowResponse(string type) - { - Console.WriteLine($"It took {api.responseTime} ms to {type}"); - } + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetCurrentProcess(); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern ushort GlobalFindAtom(string lpString); static void Main(string[] args) { + + securityChecks(); + Console.Title = "Loader"; Console.WriteLine("\n\n Connecting.."); KeyAuthApp.init(); @@ -44,7 +53,7 @@ static void Main(string[] args) { Console.WriteLine("\n Status: " + KeyAuthApp.response.message); Thread.Sleep(1500); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } Console.Write("\n [1] Login\n [2] Register\n [3] Upgrade\n [4] License key only\n [5] Forgot password\n\n Choose option: "); @@ -81,7 +90,7 @@ static void Main(string[] args) // don't proceed to app, user hasn't authenticated yet. Console.WriteLine("\n Status: " + KeyAuthApp.response.message); Thread.Sleep(2500); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); break; case 4: Console.Write("\n\n Enter license: "); @@ -97,12 +106,12 @@ static void Main(string[] args) // don't proceed to app, user hasn't authenticated yet. Console.WriteLine("\n Status: " + KeyAuthApp.response.message); Thread.Sleep(2500); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); break; default: Console.WriteLine("\n\n Invalid Selection"); Thread.Sleep(2500); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); break; // no point in this other than to not get error from IDE } @@ -110,18 +119,20 @@ static void Main(string[] args) { Console.WriteLine("\n Status: " + KeyAuthApp.response.message); Thread.Sleep(2500); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } Console.WriteLine("\n Logged In!"); // at this point, the client has been authenticated. Put the code you want to run after here + if(string.IsNullOrEmpty(KeyAuthApp.response.message)) TerminateProcess(GetCurrentProcess(), 1); + // user data Console.WriteLine("\n User data:"); Console.WriteLine(" Username: " + KeyAuthApp.user_data.username); Console.WriteLine(" IP address: " + KeyAuthApp.user_data.ip); Console.WriteLine(" Hardware-Id: " + KeyAuthApp.user_data.hwid); Console.WriteLine(" Created at: " + UnixTimeToDateTime(long.Parse(KeyAuthApp.user_data.createdate))); - if (!String.IsNullOrEmpty(KeyAuthApp.user_data.lastlogin)) // don't show last login on register since there is no last login at that point + if (!string.IsNullOrEmpty(KeyAuthApp.user_data.lastlogin)) // don't show last login on register since there is no last login at that point Console.WriteLine(" Last login at: " + UnixTimeToDateTime(long.Parse(KeyAuthApp.user_data.lastlogin))); Console.WriteLine(" Your subscription(s):"); for (var i = 0; i < KeyAuthApp.user_data.subscriptions.Count; i++) @@ -130,7 +141,7 @@ static void Main(string[] args) } Console.WriteLine("\n Closing in five seconds..."); - Thread.Sleep(5000); + Thread.Sleep(-1); Environment.Exit(0); } @@ -155,6 +166,52 @@ public static DateTime UnixTimeToDateTime(long unixtime) return dtDateTime; } + static void checkAtom() + { + Thread atomCheckThread = new Thread(() => + { + while (true) + { + Thread.Sleep(60000); // give people 1 minute to login + + ushort foundAtom = GlobalFindAtom(KeyAuthApp.ownerid); + if (foundAtom == 0) + { + TerminateProcess(GetCurrentProcess(), 1); + } + } + }); + + atomCheckThread.IsBackground = true; // Ensure the thread does not block program exit + atomCheckThread.Start(); + } + + static void securityChecks() + { + // check if the Loader was executed by a different program + var frames = new StackTrace().GetFrames(); + foreach (var frame in frames) + { + MethodBase method = frame.GetMethod(); + if (method != null && method.DeclaringType?.Assembly != Assembly.GetExecutingAssembly()) + { + TerminateProcess(GetCurrentProcess(), 1); + } + } + + // check if HarmonyLib is attempting to poison our program + var harmonyAssembly = AppDomain.CurrentDomain + .GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == "0Harmony"); + + if (harmonyAssembly != null) + { + TerminateProcess(GetCurrentProcess(), 1); + } + + checkAtom(); + } + static void autoUpdate() { if (KeyAuthApp.response.message == "invalidver") diff --git a/Form/Ed25519.cs b/Form/Ed25519.cs new file mode 100644 index 0000000..20d1480 --- /dev/null +++ b/Form/Ed25519.cs @@ -0,0 +1,322 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Security.Cryptography; + +namespace Cryptographic +{ + /* Ported and refactored from Java to C# by Hans Wolff, 10/10/2013 + * Released to the public domain + * / + + /* Java code written by k3d3 + * Source: https://github.com/k3d3/ed25519-java/blob/master/ed25519.java + * Released to the public domain + */ + + public class Ed25519 + { + private static byte[] ComputeHash(byte[] m) + { + using (var sha512 = SHA512.Create()) // System.Security.Cryptography + { + return sha512.ComputeHash(m); + } + } + + private static BigInteger ExpMod(BigInteger number, BigInteger exponent, BigInteger modulo) + { + BigInteger result = BigInteger.One; + BigInteger baseVal = number.Mod(modulo); + + while (exponent > 0) + { + if (!exponent.IsEven) + { + result = (result * baseVal).Mod(modulo); + } + baseVal = (baseVal * baseVal).Mod(modulo); + exponent /= 2; + } + + return result; + } + + + private static readonly Dictionary InverseCache = new Dictionary(); + + private static BigInteger Inv(BigInteger x) + { + if (!InverseCache.ContainsKey(x)) + { + InverseCache[x] = ExpMod(x, Qm2, Q); + } + return InverseCache[x]; + } + + private static BigInteger RecoverX(BigInteger y) + { + BigInteger y2 = y * y; + BigInteger xx = (y2 - 1) * Inv(D * y2 + 1); + BigInteger x = ExpMod(xx, Qp3 / Eight, Q); + if (!(x * x - xx).Mod(Q).Equals(BigInteger.Zero)) + { + x = (x * I).Mod(Q); + } + if (!x.IsEven) + { + x = Q - x; + } + return x; + } + + private static Tuple Edwards(BigInteger px, BigInteger py, BigInteger qx, BigInteger qy) + { + BigInteger xx12 = px * qx; + BigInteger yy12 = py * qy; + BigInteger dtemp = D * xx12 * yy12; + BigInteger x3 = (px * qy + qx * py) * (Inv(1 + dtemp)); + BigInteger y3 = (py * qy + xx12) * (Inv(1 - dtemp)); + return new Tuple(x3.Mod(Q), y3.Mod(Q)); + } + + private static Tuple EdwardsSquare(BigInteger x, BigInteger y) + { + BigInteger xx = x * x; + BigInteger yy = y * y; + BigInteger dtemp = D * xx * yy; + BigInteger x3 = (2 * x * y) * (Inv(1 + dtemp)); + BigInteger y3 = (yy + xx) * (Inv(1 - dtemp)); + return new Tuple(x3.Mod(Q), y3.Mod(Q)); + } + private static Tuple ScalarMul(Tuple point, BigInteger scalar) + { + var result = new Tuple(BigInteger.Zero, BigInteger.One); // Neutral element + var basePoint = point; + + while (scalar > 0) + { + if (!scalar.IsEven) // If the current bit is set, add the base point to the result + { + result = Edwards(result.Item1, result.Item2, basePoint.Item1, basePoint.Item2); + } + + basePoint = EdwardsSquare(basePoint.Item1, basePoint.Item2); // Double the point + scalar >>= 1; // Move to the next bit in the scalar + } + + return result; + } + + public static byte[] EncodeInt(BigInteger y) + { + byte[] nin = y.ToByteArray(); + var nout = new byte[Math.Max(nin.Length, 32)]; + Array.Copy(nin, nout, nin.Length); + return nout; + } + + public static byte[] EncodePoint(BigInteger x, BigInteger y) + { + byte[] nout = EncodeInt(y); + nout[nout.Length - 1] |= (x.IsEven ? (byte)0 : (byte)0x80); + return nout; + } + + private static int GetBit(byte[] h, int i) + { + return h[i / 8] >> (i % 8) & 1; + } + + public static byte[] PublicKey(byte[] signingKey) + { + byte[] h = ComputeHash(signingKey); + BigInteger a = TwoPowBitLengthMinusTwo; + for (int i = 3; i < (BitLength - 2); i++) + { + var bit = GetBit(h, i); + if (bit != 0) + { + a += TwoPowCache[i]; + } + } + var bigA = ScalarMul(B, a); + return EncodePoint(bigA.Item1, bigA.Item2); + } + + private static BigInteger HashInt(byte[] m) + { + byte[] h = ComputeHash(m); + BigInteger hsum = BigInteger.Zero; + for (int i = 0; i < 2 * BitLength; i++) + { + var bit = GetBit(h, i); + if (bit != 0) + { + hsum += TwoPowCache[i]; + } + } + return hsum; + } + + public static byte[] Signature(byte[] message, byte[] signingKey, byte[] publicKey) + { + byte[] h = ComputeHash(signingKey); + BigInteger a = TwoPowBitLengthMinusTwo; + for (int i = 3; i < (BitLength - 2); i++) + { + var bit = GetBit(h, i); + if (bit != 0) + { + a += TwoPowCache[i]; + } + } + + BigInteger r; + using (var rsub = new MemoryStream((BitLength / 8) + message.Length)) + { + rsub.Write(h, BitLength / 8, BitLength / 4 - BitLength / 8); + rsub.Write(message, 0, message.Length); + r = HashInt(rsub.ToArray()); + } + var bigR = ScalarMul(B, r); + BigInteger s; + var encodedBigR = EncodePoint(bigR.Item1, bigR.Item2); + using (var stemp = new MemoryStream(32 + publicKey.Length + message.Length)) + { + stemp.Write(encodedBigR, 0, encodedBigR.Length); + stemp.Write(publicKey, 0, publicKey.Length); + stemp.Write(message, 0, message.Length); + s = (r+ HashInt(stemp.ToArray()) * a).Mod(L); + } + + using (var nout = new MemoryStream(64)) + { + nout.Write(encodedBigR, 0, encodedBigR.Length); + var encodeInt = EncodeInt(s); + nout.Write(encodeInt, 0, encodeInt.Length); + return nout.ToArray(); + } + } + + private static bool IsOnCurve(BigInteger x, BigInteger y) + { + BigInteger xx = x * x; + BigInteger yy = y * y; + BigInteger dxxyy = D * yy * xx; + return (yy - xx - dxxyy - 1).Mod(Q).Equals(BigInteger.Zero); + } + + private static BigInteger DecodeInt(byte[] s) + { + return new BigInteger(s) & Un; + } + + private static Tuple DecodePoint(byte[] pointBytes) + { + BigInteger y = new BigInteger(pointBytes) & Un; + BigInteger x = RecoverX(y); + if ((x.IsEven ? 0 : 1) != GetBit(pointBytes, BitLength - 1)) + { + x = Q - x; + } + var point = new Tuple(x, y); + if (!IsOnCurve(x, y)) throw new ArgumentException("Decoding point that is not on curve"); + return point; + } + + public static bool CheckValid(byte[] signature, byte[] message, byte[] publicKey) + { + Console.Write("."); // ... dots in console + if (signature.Length != BitLength / 4) throw new ArgumentException("Signature length is wrong"); + if (publicKey.Length != BitLength / 8) throw new ArgumentException("Public key length is wrong"); + + byte[] rByte = Arrays.CopyOfRange(signature, 0, BitLength / 8); + + var r = DecodePoint(rByte); + var a = DecodePoint(publicKey); + + byte[] sByte = Arrays.CopyOfRange(signature, BitLength / 8, BitLength / 4); + + BigInteger s = DecodeInt(sByte); + BigInteger h; + + using (var stemp = new MemoryStream(32 + publicKey.Length + message.Length)) + { + var encodePoint = EncodePoint(r.Item1, r.Item2); + stemp.Write(encodePoint, 0, encodePoint.Length); + stemp.Write(publicKey, 0, publicKey.Length); + stemp.Write(message, 0, message.Length); + h = HashInt(stemp.ToArray()); + } + + Console.Write("."); // ... dots in console + var ra = ScalarMul(B, s); + Console.Write("."); // ... dots in console + var ah = ScalarMul(a, h); + var rb = Edwards(r.Item1, r.Item2, ah.Item1, ah.Item2); + if (!ra.Item1.Equals(rb.Item1) || !ra.Item2.Equals(rb.Item2)) + return false; + return true; + } + + private const int BitLength = 256; + + private static readonly BigInteger TwoPowBitLengthMinusTwo = BigInteger.Pow(2, BitLength - 2); + private static readonly BigInteger[] TwoPowCache = Enumerable.Range(0, 2 * BitLength).Select(i => BigInteger.Pow(2, i)).ToArray(); + + private static readonly BigInteger Q = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819949"); + + private static readonly BigInteger Qm2 = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819947"); + + private static readonly BigInteger Qp3 = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819952"); + + private static readonly BigInteger L = + BigInteger.Parse("7237005577332262213973186563042994240857116359379907606001950938285454250989"); + + private static readonly BigInteger D = + BigInteger.Parse("-4513249062541557337682894930092624173785641285191125241628941591882900924598840740"); + + private static readonly BigInteger I = + BigInteger.Parse("19681161376707505956807079304988542015446066515923890162744021073123829784752"); + + private static readonly BigInteger By = + BigInteger.Parse("46316835694926478169428394003475163141307993866256225615783033603165251855960"); + + private static readonly BigInteger Bx = + BigInteger.Parse("15112221349535400772501151409588531511454012693041857206046113283949847762202"); + + private static readonly Tuple B = new Tuple(Bx.Mod(Q), By.Mod(Q)); + + private static readonly BigInteger Un = + BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819967"); + + private static readonly BigInteger Two = new BigInteger(2); + private static readonly BigInteger Eight = new BigInteger(8); + } + + internal static class Arrays + { + public static byte[] CopyOfRange(byte[] original, int from, int to) + { + int length = to - from; + var result = new byte[length]; + Array.Copy(original, from, result, 0, length); + return result; + } + } + + internal static class BigIntegerHelpers + { + public static BigInteger Mod(this BigInteger num, BigInteger modulo) + { + var result = num % modulo; + return result < 0 ? result + modulo : result; + } + } +} \ No newline at end of file diff --git a/Form/KeyAuth.cs b/Form/KeyAuth.cs index b930669..88f39f4 100644 --- a/Form/KeyAuth.cs +++ b/Form/KeyAuth.cs @@ -12,41 +12,51 @@ using System.Security.Cryptography.X509Certificates; using System.Net.Security; using System.Threading; -using System.Runtime.CompilerServices; +using Cryptographic; +using System.Runtime.InteropServices; namespace KeyAuth { public class api { - public string name, ownerid, secret, version, path; - public static long responseTime; + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetCurrentProcess(); + + // Import the required Atom Table functions from kernel32.dll + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern ushort GlobalAddAtom(string lpString); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern ushort GlobalFindAtom(string lpString); + + public string name, ownerid, version, path, seed; /// /// Set up your application credentials in order to use keyauth /// /// Application Name /// Your OwnerID, found in your account settings. - /// Application Secret /// Application Version, if version doesnt match it will open the download link you set up in your application settings and close the app, if empty the app will close - public api(string name, string ownerid, string secret, string version, string path = null) + public api(string name, string ownerid, string version, string path = null) { - if (ownerid.Length != 10 || secret.Length != 64) + if (ownerid.Length != 10) { Process.Start("https://youtube.com/watch?v=RfDTdiBq4_o"); Process.Start("https://keyauth.cc/app/"); Thread.Sleep(2000); error("Application not setup correctly. Please watch the YouTube video for setup."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } this.name = name; this.ownerid = ownerid; - this.secret = secret; - this.version = version; - this.path = path; + this.path = path; } #region structures @@ -71,6 +81,9 @@ private class response_structure [DataMember] public string message { get; set; } + [DataMember] + public string ownerid { get; set; } + [DataMember] public string download { get; set; } @@ -141,62 +154,98 @@ private class app_data_structure /// public void init() { - string sentKey = encryption.iv_key(); - enckey = sentKey + "-" + secret; + Random random = new Random(); + + // Generate a random length for the string (let's assume between 5 and 50 characters) + int length = random.Next(5, 51); // Min length: 5, Max length: 50 + + StringBuilder sb = new StringBuilder(length); + + // Define the range of printable ASCII characters (32-126) + for (int i = 0; i < length; i++) + { + // Generate a random printable ASCII character + char randomChar = (char)random.Next(32, 127); // ASCII 32 to 126 + sb.Append(randomChar); + } + + seed = sb.ToString(); + checkAtom(); + var values_to_upload = new NameValueCollection { ["type"] = "init", ["ver"] = version, ["hash"] = checksum(Process.GetCurrentProcess().MainModule.FileName), - ["enckey"] = sentKey, ["name"] = name, ["ownerid"] = ownerid }; - if (!string.IsNullOrEmpty(path)) - { + if (!string.IsNullOrEmpty(path)) + { values_to_upload.Add("token", File.ReadAllText(path)); values_to_upload.Add("thash", TokenHash(path)); - } + } var response = req(values_to_upload); if (response == "KeyAuth_Invalid") { error("Application not found"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) + if (json.ownerid == ownerid) { - if (json.newSession) + load_response_struct(json); + if (json.success) + { + sessionid = json.sessionid; + initialized = true; + } + else if (json.message == "invalidver") { - Thread.Sleep(100); + app_data.downloadLink = json.download; } - sessionid = json.sessionid; - initialized = true; } - else if (json.message == "invalidver") + else { - app_data.downloadLink = json.download; + TerminateProcess(GetCurrentProcess(), 1); } + } + + void checkAtom() + { + Thread atomCheckThread = new Thread(() => + { + while (true) + { + Thread.Sleep(60000); // give people 1 minute to login + ushort foundAtom = GlobalFindAtom(seed); + if (foundAtom == 0) + { + TerminateProcess(GetCurrentProcess(), 1); + } + } + }); + + atomCheckThread.IsBackground = true; // Ensure the thread does not block program exit + atomCheckThread.Start(); } public static string TokenHash(string tokenPath) { - using (var sha256 = SHA256.Create()) - { + using (var sha256 = SHA256.Create()) + { using (var s = File.OpenRead(tokenPath)) { - byte[] bytes = sha256.ComputeHash(s); - return BitConverter.ToString(bytes).Replace("-", string.Empty); + byte[] bytes = sha256.ComputeHash(s); + return BitConverter.ToString(bytes).Replace("-", string.Empty); } } - } - + } /// /// Checks if Keyauth is been Initalized /// @@ -205,7 +254,7 @@ public void CheckInit() if (!initialized) { error("You must run the function KeyAuthApp.init(); first"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } } @@ -214,7 +263,7 @@ public void CheckInit() /// /// Subscription Number /// You can choose between Days,Hours,Months - public string expirydaysleft(string Type, int subscription) + public string expirydaysleft(string Type,int subscription) { CheckInit(); @@ -262,9 +311,19 @@ public void register(string username, string pass, string key, string email = "" var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - load_user_data(json.info); + if (json.ownerid == ownerid) + { + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + if (json.success) + load_user_data(json.info); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Allow users to enter their account information and recieve an email to reset their password. @@ -315,12 +374,22 @@ public void login(string username, string pass) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - load_user_data(json.info); + if (json.ownerid == ownerid) + { + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + if (json.success) + load_user_data(json.info); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } - public void logout() + public void logout() { CheckInit(); @@ -335,7 +404,14 @@ public void logout() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } public void web_login() @@ -346,7 +422,7 @@ public void web_login() string datastore, datastore2, outputten; - start: + start: HttpListener listener = new HttpListener(); @@ -404,26 +480,35 @@ public void web_login() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - bool success = true; - - if (json.success) + if (json.ownerid == ownerid) { - load_user_data(json.info); + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); - responsepp.StatusCode = 420; - responsepp.StatusDescription = "SHEESH"; + if (json.success) + { + load_user_data(json.info); + + responsepp.StatusCode = 420; + responsepp.StatusDescription = "SHEESH"; + } + else + { + Console.WriteLine(json.message); + responsepp.StatusCode = (int)HttpStatusCode.OK; + responsepp.StatusDescription = json.message; + success = false; + } } else { - Console.WriteLine(json.message); - responsepp.StatusCode = (int)HttpStatusCode.OK; - responsepp.StatusDescription = json.message; - success = false; + TerminateProcess(GetCurrentProcess(), 1); } - byte[] buffer = Encoding.UTF8.GetBytes("Whats up?"); + byte[] buffer = Encoding.UTF8.GetBytes("Complete"); responsepp.ContentLength64 = buffer.Length; Stream output = responsepp.OutputStream; @@ -432,7 +517,7 @@ public void web_login() listener.Stop(); if (!success) - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } @@ -499,8 +584,15 @@ public void upgrade(string username, string key) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - json.success = false; - load_response_struct(json); + if (json.ownerid == ownerid) + { + json.success = false; + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// @@ -526,9 +618,20 @@ public void license(string key) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - load_user_data(json.info); + + if (json.ownerid == ownerid) + { + GlobalAddAtom(seed); + GlobalAddAtom(ownerid); + + load_response_struct(json); + if (json.success) + load_user_data(json.info); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Checks if the current session is validated or not @@ -548,7 +651,14 @@ public void check() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Change the data of an existing user variable, *User must be logged in* @@ -572,7 +682,14 @@ public void setvar(string var, string data) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Gets the an existing user variable @@ -595,9 +712,16 @@ public string getvar(string var) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return json.response; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return json.response; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } return null; } /// @@ -619,7 +743,14 @@ public void ban(string reason = null) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); + if (json.ownerid == ownerid) + { + load_response_struct(json); + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } } /// /// Gets an existing global variable @@ -642,9 +773,16 @@ public string var(string varid) var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return json.message; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return json.message; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } return null; } /// @@ -772,10 +910,19 @@ public bool checkblack() var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return true; - return false; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return true; + else + return false; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } + return true; // return yes blacklisted if the OwnerID is spoofed } /// /// Sends a request to a webhook that you've added in the dashboard in a safe way without it being showed for example a http debugger @@ -804,9 +951,16 @@ public string webhook(string webid, string param, string body = "", string contt var response = req(values_to_upload); var json = response_decoder.string_to_generic(response); - load_response_struct(json); - if (json.success) - return json.response; + if (json.ownerid == ownerid) + { + load_response_struct(json); + if (json.success) + return json.response; + } + else + { + TerminateProcess(GetCurrentProcess(), 1); + } return null; } /// @@ -893,7 +1047,7 @@ public static string checksum(string filename) return result; } - public static void LogEvent(string content) + public static void LogEvent(string content) { string exeName = Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location); @@ -912,7 +1066,6 @@ public static void LogEvent(string content) content = RedactField(content, "sessionid"); content = RedactField(content, "ownerid"); content = RedactField(content, "app"); - content = RedactField(content, "secret"); content = RedactField(content, "version"); content = RedactField(content, "fileid"); content = RedactField(content, "webhooks"); @@ -931,6 +1084,7 @@ public static void LogEvent(string content) private static string RedactField(string content, string fieldName) { + // Basic pattern matching to replace values of sensitive fields string pattern = $"\"{fieldName}\":\"[^\"]*\""; string replacement = $"\"{fieldName}\":\"REDACTED\""; @@ -955,7 +1109,7 @@ public static void error(string message) } File.AppendAllText(file, DateTime.Now + $" > {message}" + Environment.NewLine); - + Process.Start(new ProcessStartInfo("cmd.exe", $"/c start cmd /C \"color b && title Error && echo {message} && timeout /t 5\"") { CreateNoWindow = true, @@ -963,9 +1117,9 @@ public static void error(string message) RedirectStandardError = true, UseShellExecute = false }); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } - + private static string req(NameValueCollection post_data) { try @@ -976,17 +1130,11 @@ private static string req(NameValueCollection post_data) ServicePointManager.ServerCertificateValidationCallback += assertSSL; - Stopwatch stopwatch = new Stopwatch(); - stopwatch.Start(); - - var raw_response = client.UploadValues("https://keyauth.win/api/1.2/", post_data); - - stopwatch.Stop(); - responseTime = stopwatch.ElapsedMilliseconds; + var raw_response = client.UploadValues("https://keyauth.win/api/1.3/", post_data); ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; - sigCheck(Encoding.UTF8.GetString(raw_response), client.ResponseHeaders["signature"], post_data.Get(0)); + sigCheck(Encoding.UTF8.GetString(raw_response), client.ResponseHeaders, post_data.Get(0)); LogEvent(Encoding.Default.GetString(raw_response) + "\n"); @@ -1001,19 +1149,19 @@ private static string req(NameValueCollection post_data) case (HttpStatusCode)429: // client hit our rate limit error("You're connecting too fast to loader, slow down."); LogEvent("You're connecting too fast to loader, slow down."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); return ""; default: // site won't resolve. you should use keyauth.uk domain since it's not blocked by any ISPs error("Connection failure. Please try again, or contact us for help."); LogEvent("Connection failure. Please try again, or contact us for help."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); return ""; } } } private static bool assertSSL(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { + { if ((!certificate.Issuer.Contains("Google Trust Services") && !certificate.Issuer.Contains("Let's Encrypt")) || sslPolicyErrors != SslPolicyErrors.None) { error("SSL assertion fail, make sure you're not debugging Network. Disable internet firewall on router if possible. & echo: & echo If not, ask the developer of the program to use custom domains to fix this."); @@ -1023,28 +1171,61 @@ private static bool assertSSL(object sender, X509Certificate certificate, X509Ch return true; } - private static void sigCheck(string resp, string signature, string type) + private static void sigCheck(string resp, WebHeaderCollection headers, string type) { - if (type == "log" || type == "file") // log doesn't return a response. + if(type == "log" || type == "file") // log doesn't return a response. { return; } try { - string clientComputed = encryption.HashHMAC((type == "init") ? enckey.Substring(17, 64) : enckey, resp); - if (!encryption.CheckStringsFixedTime(clientComputed, signature)) + string signature = headers["x-signature-ed25519"]; + string timestamp = headers["x-signature-timestamp"]; + + // Try to parse the input string to a long Unix timestamp + if (!long.TryParse(timestamp, out long unixTimestamp)) + { + TerminateProcess(GetCurrentProcess(), 1); + } + + // Convert the Unix timestamp to a DateTime object (in UTC) + DateTime timestampTime = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp).UtcDateTime; + + // Get the current UTC time + DateTime currentTime = DateTime.UtcNow; + + // Calculate the difference between the current time and the timestamp + TimeSpan timeDifference = currentTime - timestampTime; + + // Check if the timestamp is within 15 seconds of the current time + if (timeDifference.TotalSeconds > 15) + { + TerminateProcess(GetCurrentProcess(), 1); + } + + var byteSig = encryption.str_to_byte_arr(signature); + var byteKey = encryption.str_to_byte_arr("5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b"); + // ... read the body from the request ... + // ... add the timestamp and convert it to a byte[] ... + string body = timestamp + resp; + var byteBody = Encoding.Default.GetBytes(body); + + Console.Write(" Authenticating"); // there's also ... dots being created inside the CheckValid() function BELOW + + bool signatureValid = Ed25519.CheckValid(byteSig, byteBody, byteKey); // the ... dots in the console are from this function! + if (!signatureValid) { error("Signature checksum failed. Request was tampered with or session ended most likely. & echo: & echo Response: " + resp); LogEvent(resp + "\n"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } } catch { error("Signature checksum failed. Request was tampered with or session ended most likely. & echo: & echo Response: " + resp); LogEvent(resp + "\n"); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); } } @@ -1122,6 +1303,12 @@ private void load_response_struct(response_structure data) public static class encryption { + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetCurrentProcess(); + public static string HashHMAC(string enckey, string resp) { byte[] key = Encoding.UTF8.GetBytes(enckey); @@ -1151,26 +1338,11 @@ public static byte[] str_to_byte_arr(string hex) catch { api.error("The session has ended, open program again."); - Environment.Exit(0); + TerminateProcess(GetCurrentProcess(), 1); return null; } } - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] - public static bool CheckStringsFixedTime(string str1, string str2) - { - if (str1.Length != str2.Length) - { - return false; - } - var result = 0; - for (var i = 0; i < str1.Length; i++) - { - result |= str1[i] ^ str2[i]; - } - return result == 0; - } - public static string iv_key() => Guid.NewGuid().ToString().Substring(0, 16); } diff --git a/Form/Loader.csproj b/Form/Loader.csproj index 605c715..04891b5 100644 --- a/Form/Loader.csproj +++ b/Form/Loader.csproj @@ -39,6 +39,7 @@ + @@ -47,6 +48,7 @@ + Form diff --git a/Form/Login.cs b/Form/Login.cs index 2a8aeba..a440a60 100644 --- a/Form/Login.cs +++ b/Form/Login.cs @@ -20,19 +20,10 @@ public partial class Login : Form public static api KeyAuthApp = new api( name: "", // Application Name ownerid: "", // Owner ID - secret: "", // Application Secret version: "" // Application Version /* //path: @"Your_Path_Here" // (OPTIONAL) see tutorial here https://www.youtube.com/watch?v=I9rxt821gMk&t=1s ); - //This will display how long it took to make a request in ms. The param "type" is for "login", "register", "init", etc... but that is optional, as well as this function. Ideally you can just put a label or MessageBox.Show($"Request took {api.responseTime}"), but either works. - // if you would like to use this method, simply put it in any function and pass the param ... ShowResponse("TypeHere"); - private void ShowResponse(string type) - { - //responseTimeLbl.Text = $"It took {api.responseTime} ms to {type}"; // you need to create a label called responseTimeLbl to display to a label. - MessageBox.Show($"It took {api.responseTime} msg to {type}"); - } - public Login() { InitializeComponent(); diff --git a/Form/bin/Debug/Siticone.UI.dll b/Form/bin/Debug/Siticone.UI.dll deleted file mode 100644 index 7e25dd8..0000000 Binary files a/Form/bin/Debug/Siticone.UI.dll and /dev/null differ