Exemple #1
0
        static RandomProvider()
        {
            psuedoRandom        = new SystemRandomProvider();
            cryptographicRandom = new CryptoRandomProvider();

            SelectedRandomizationType = RandomizationType.Pseudorandom;
        }
Exemple #2
0
        public static void Main(string[] args)
        {
            // Create a client session manager and allow sessions to remain valid for up to 5 minutes of inactivity (300 seconds)
            SessionManager manager = new SessionManager(300 * TimeSpan.TicksPerSecond, 20);

            SetConsoleCtrlHandler(i => {
                db.Flush(); // Ensures that the database is flushed before the program exits
                return(false);
            }, true);

            // Create a secure random provider and start getting RSA stuff
            CryptoRandomProvider random = new CryptoRandomProvider();
            Task <RSA>           t      = new Task <RSA>(() =>
            {
                RSA rsa = new RSA(Resources.e_0x100, Resources.n_0x100, Resources.d_0x100);
                if (rsa == null)
                {
                    Output.Fatal("No RSA keys found! Server identity will not be verifiable!");
                    Output.Info("Generating session-specific RSA-keys...");
                    rsa = new RSA(128, 8, 7, 5);
                    rsa.Save("0x100");
                    Output.Info("Done!");
                }
                return(rsa);
            });

            t.Start();

            // Local methods to simplify common operations
            bool ParseDataPair(string cmd, out string user, out string pass)
            {
                int idx = cmd.IndexOf(':');

                user = "";
                pass = "";
                if (idx == -1)
                {
                    return(false);
                }
                user = cmd.Substring(0, idx);
                try
                {
                    user = user.FromBase64String();
                    pass = cmd.Substring(idx + 1).FromBase64String();
                }
                catch
                {
                    Output.Error($"Recieved problematic username or password! (User: \"{user}\")");
                    return(false);
                }
                return(true);
            }

            int ParseDataSet(string cmd, out string[] data)
            {
                List <string> gen = new List <string>();
                int           idx;

                while ((idx = cmd.IndexOf(':')) != -1)
                {
                    try
                    {
                        gen.Add(cmd.Substring(0, idx).FromBase64String());
                    }
                    catch
                    {
                        data = null;
                        return(-1); // Hard error
                    }
                    cmd = cmd.Substring(idx + 1);
                }
                try
                {
                    gen.Add(cmd.FromBase64String());
                }
                catch
                {
                    data = null;
                    return(-1); // Hard error
                }
                data = gen.ToArray();
                return(gen.Count);
            }

            string[] ParseCommand(string cmd, out long id)
            {
                int    idx = cmd.IndexOf(':'), idx1;
                string sub;

                if (idx == -1 || !(sub = cmd.Substring(idx + 1)).Contains(':') || !long.TryParse(sub.Substring(0, idx1 = sub.IndexOf(':')), out id))
                {
                    id = 0;
                    return(null);
                }
                return(new string[] { cmd.Substring(0, idx), sub.Substring(idx1 + 1) });
            }

            string GenerateResponse(long id, dynamic d) => id + ":" + d.ToString();
            string ErrorResponse(long id, string i18n = null) => GenerateResponse(id, $"ERROR{(i18n==null?"":":"+VERBOSE_RESPONSE)}{i18n??""}");

            bool GetUser(string sid, out Database.User user)
            {
                user = manager.GetUser(sid);
                bool exists = user != null;

                if (exists)
                {
                    user = db.GetUser(user.Name);
                }
                return(exists && user != null);
            }

            bool GetAccount(string name, Database.User user, out Database.Account acc)
            {
                acc = user.accounts.FirstOrDefault(a => a.name.Equals(name));
                return(acc != null);
            }

            // Create server
            NetServer server = new NetServer(
                EllipticDiffieHellman.Curve25519(EllipticDiffieHellman.Curve25519_GeneratePrivate(random)),
                80,
                (string r, Dictionary <string, string> associations, ref bool s) =>
            {
                string[] cmd = ParseCommand(r, out long id);

                // Handle corrupt or badly formatted messages from client
                if (cmd == null)
                {
                    return(ErrorResponse(-1, "corrupt"));
                }

                // Server endpoints
                switch (cmd[0])
                {
                case "RmUsr":
                    {
                        if (!GetUser(cmd[1], out var user))
                        {
                            if (verbosity > 0)
                            {
                                Output.Error($"Could not delete user from session as session isn't valid. (SessionID=\"{cmd[1]}\")");
                            }
                            return(ErrorResponse(id, "badsession"));
                        }
                        manager.Expire(user);
                        db.RemoveUser(user);
                        if (verbosity > 0)
                        {
                            Output.Info($"Removed user \"{user.Name}\" (SessionID={cmd[1]})");
                        }
                        return(GenerateResponse(id, true));
                    }

                case "Auth":         // Log in to a user account (get a session id)
                    {
                        if (!ParseDataPair(cmd[1], out string user, out string pass))
                        {
                            if (verbosity > 0)
                            {
                                Output.Error($"Recieved problematic username or password! (User: \"{user}\")");
                            }
                            return(ErrorResponse(id));
                        }
                        Database.User usr = db.GetUser(user);
                        if (usr == null || !usr.Authenticate(pass))
                        {
                            if (verbosity > 0)
                            {
                                Output.Error("Authentcation failure for user: "******"ERROR");
                        Output.Positive("Authentication success for user: "******"\nSession: " + sess);
                        associations["session"] = sess;
                        return(GenerateResponse(id, sess));
                    }
Exemple #3
0
        static void Main(string[] args)
        {
            Console.Write("Enter your personal password: "******"Generating authentication code...");

            // Generate a password-based Message Authentication Code (with salt to prevent rainbowtables) to verify the user identity against the server
            // This string will be used as our database key: a (pseudo-)unique identifier which, for all intents and purposes, can be as public as we like since it doesn't do an attacker any good to know it
            string auth = Support.ToHexString(KDF.PBKDF2(KDF.HMAC_SHA1, key.ToUTF8Bytes(), "NoRainbow".ToUTF8Bytes(), 8192, 128));

            // Create private encryption/decryption algorithm for processing private (encrypted) data stored on server
            Rijndael128    privCrypt = new Rijndael128(key);
            RandomProvider provider  = new CryptoRandomProvider();

            bool connected = false;
            bool load      = false;
            // AES key used for communication is randomly chosen by generating anywhere between 1 and 511 random bytes as the password for PBKDF2-HMAC-SHA1
            NetClient client = new NetClient(new Rijndael128(provider.GetBytes(provider.NextInt(511) + 1).ToUTF8String()), ParseIP(), ParsePort(), (string message, out bool keepAlive) =>
            {
                if (message.StartsWith("M-"))
                {
                    // Handle a blank response
                    if (message.Length == 2)
                    {
                        Console.WriteLine("No messages exist with your password");
                    }
                    else
                    {
                        string[] msgs = null;
                        try
                        {
                            msgs = Support.DeserializeString(message.Substring(2));
                        }
                        catch (Exception) { Console.WriteLine("The server seems to have sent an incorrect message. The stored messages could not be read!"); }

                        foreach (var cmsg in msgs)
                        {
                            try
                            {
                                // Decrypt each message with the supplied decryptor
                                byte[] messages_pad = privCrypt.Decrypt(Convert.FromBase64String(cmsg));
                                int len             = Support.ReadInt(messages_pad, 0);
                                string messages     = messages_pad.SubArray(4, len + 4).ToUTF8String();
                                Console.WriteLine(messages);
                            }
                            catch (Exception) { /* Ignore corrupt message (maybe do something else here?) */ }
                        }


                        Console.WriteLine("\nPress any key to continue...");
                        Console.ReadKey();
                        Console.Clear();
                    }
                    load = false;
                }

                // Tell the client object to keep the connection alive
                keepAlive = true;

                // Don't respond
                return(null);
            }, cli =>
            {
                Console.WriteLine("Connected to server!");
                connected = true;
            });

            // Server-connection-attempt loop (mostly just UI/UX stuff)
            do
            {
                try
                {
                    Console.WriteLine("Connecting to server...");
                    client.Connect(); // <----- Only important line in this entire loop
                    break;
                }
                catch (Exception)
                {
                    Console.Write("The server rejected the connection (probably because the server isn't running). Try again? (Y/n): ");
                    if (Console.In.ReadYNBool("n"))
                    {
                        Console.WriteLine("OK. Exiting...");
                        Thread.Sleep(2500);
                        Environment.Exit(0);
                    }
                    Console.Clear();
                }
            } while (true);

            while (!connected)
            {
                Thread.Sleep(125);
            }

            Console.WriteLine();

            bool alive = true;

            while (alive)
            {
                // Show selection menu
                switch (DoSelect())
                {
                case 1:
                {
                    // Get and send a message to the server
                    Console.Clear();
                    Console.Write("Message to send to server: ");
                    string message = Console.ReadLine();
                    if (message.Length == 0)
                    {
                        message = "\0";                              // Blank messages are parsed as a null byte
                    }
                    // Encrypt the message with our personal AES object (which hopefully only we know)
                    byte[] toSend = privCrypt.Encrypt(NetSupport.WithHeader(message.ToUTF8Bytes()));

                    // Send to the server
                    if (!client.TrySend("S-" + auth + "-" + Convert.ToBase64String(toSend)))
                    {
                        Console.WriteLine("Unfortunately, an error ocurred when attempting to send your message to the server :(");
                    }
                    break;
                }

                case 2:
                {
                    // Send a request to the server for a list of all messages associated with the hex key we generated in the beginning
                    Console.Clear();
                    Console.WriteLine("Loading messages...");

                    // Send the "Load" command along with our db key
                    if (!client.TrySend("L-" + auth))
                    {
                        Console.WriteLine("Unfortunately, an error ocurred when attempting to send your message to the server :(");
                    }
                    load = true;
                    while (load)
                    {
                        Thread.Sleep(125);
                    }
                    break;
                }

                case 3:
                    Console.WriteLine("Exiting...");

                    // Await client disconnection
                    try { client.Disconnect(); }
                    catch (Exception) { }

                    // Stop program
                    Environment.Exit(0);
                    break;
                }
            }

            while (client.IsAlive)
            {
                Thread.Sleep(250);
            }
        }