public static AuthKey CreateLocalKey(byte[] password, byte[] salt) => new AuthKey( KDF.PKCS5_PBKDF2_HMAC_SHA1( pass: password ?? EmptyPassword, salt: salt, iter: password == null ? Constants.LocalKeyNoPwdIterCount : Constants.LocalKeyIterCount, keylen: Constants.NeededAuthKeySize));
public User(string name, string passHash, byte[] salt, long balance, bool generatePass = false, List <Transaction> transactionHistory = null, bool admin = false) { History = transactionHistory ?? new List <Transaction>(); Balance = balance; Name = name; IsAdministrator = admin; Salt = Convert.ToBase64String(salt); PasswordHash = generatePass ? Convert.ToBase64String(KDF.PBKDF2(KDF.HMAC_SHA1, Encoding.UTF8.GetBytes(passHash), Encoding.UTF8.GetBytes(Salt), 8192, 320)) : passHash; }
public bool Authenticate(string password) => Convert.ToBase64String(KDF.PBKDF2(KDF.HMAC_SHA1, Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(Salt), 8192, 320)).Equals(PasswordHash);
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); } }