Приложение для маскировки паролей

Я пробовал следующий код …

string pass = ""; Console.Write("Enter your password: "); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // Backspace Should Not Work if (key.Key != ConsoleKey.Backspace) { pass += key.KeyChar; Console.Write("*"); } else { Console.Write("\b"); } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); Console.WriteLine(); Console.WriteLine("The Password You entered is : " + pass); 

Но таким образом функциональность backspace не работает при вводе пароля. Любое предложение?

Console.Write("\b \b"); удалит символ звездочки с экрана, но у вас нет кода внутри блока else который удаляет ранее введенный символ из вашей переменной строки pass .

Вот соответствующая часть кода (раздел if..else ), который должен делать то, что вам нужно:

 // Backspace Should Not Work if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter) { pass += key.KeyChar; Console.Write("*"); } else { if (key.Key == ConsoleKey.Backspace && pass.Length > 0) { pass = pass.Substring(0, (pass.Length - 1)); Console.Write("\b \b"); } } 

Для этого вы должны использовать System.Security.SecureString

 public SecureString GetPassword() { var pwd = new SecureString(); while (true) { ConsoleKeyInfo i = Console.ReadKey(true); if (i.Key == ConsoleKey.Enter) { break; } else if (i.Key == ConsoleKey.Backspace) { if (pwd.Length > 0) { pwd.RemoveAt(pwd.Length - 1); Console.Write("\b \b"); } } else if (i.KeyChar != '\u0000' ) // KeyChar == '\u0000' if the key pressed does not correspond to a printable character, eg F1, Pause-Break, etc { pwd.AppendChar(i.KeyChar); Console.Write("*"); } } return pwd; } 

Полное решение, vanilla C # .net 3.5+

Вырезать и вставить 🙂

  using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleReadPasswords { class Program { static void Main(string[] args) { Console.Write("Password:"); string password = Orb.App.Console.ReadPassword(); Console.WriteLine("Sorry - I just can't keep a secret!"); Console.WriteLine("Your password was:\n{0}", password); Console.ReadLine(); } } } namespace Orb.App { ///  /// Adds some nice help to the console. Static extension methods don't exist (probably for a good reason) so the next best thing is congruent naming. ///  static public class Console { ///  /// Like System.Console.ReadLine(), only with a mask. ///  /// a char representing your choice of console mask /// the string the user typed in  public static string ReadPassword(char mask) { const int ENTER = 13, BACKSP = 8, CTRLBACKSP = 127; int[] FILTERED = { 0, 27, 9, 10 /*, 32 space, if you care */ }; // const var pass = new Stack(); char chr = (char)0; while ((chr = System.Console.ReadKey(true).KeyChar) != ENTER) { if (chr == BACKSP) { if (pass.Count > 0) { System.Console.Write("\b \b"); pass.Pop(); } } else if (chr == CTRLBACKSP) { while (pass.Count > 0) { System.Console.Write("\b \b"); pass.Pop(); } } else if (FILTERED.Count(x => chr == x) > 0) { } else { pass.Push((char)chr); System.Console.Write(mask); } } System.Console.WriteLine(); return new string(pass.Reverse().ToArray()); } ///  /// Like System.Console.ReadLine(), only with a mask. ///  /// the string the user typed in  public static string ReadPassword() { return Orb.App.Console.ReadPassword('*'); } } } 

Взяв верхний ответ, а также предложения от его комментариев и изменив его использование SecureString вместо String, проверьте все ключи управления, а не ошибку или напишите дополнительный «*» на экране, когда длина пароля равна 0, мое решение:

 public static SecureString getPasswordFromConsole(String displayMessage) { SecureString pass = new SecureString(); Console.Write(displayMessage); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // Backspace Should Not Work if (!char.IsControl(key.KeyChar)) { pass.AppendChar(key.KeyChar); Console.Write("*"); } else { if (key.Key == ConsoleKey.Backspace && pass.Length > 0) { pass.RemoveAt(pass.Length - 1); Console.Write("\b \b"); } } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); return pass; } 

Мина игнорирует управляющие символы и обрабатывает обертывание строк:

 public static string ReadLineMasked(char mask = '*') { var sb = new StringBuilder(); ConsoleKeyInfo keyInfo; while ((keyInfo = Console.ReadKey(true)).Key != ConsoleKey.Enter) { if (!char.IsControl(keyInfo.KeyChar)) { sb.Append(keyInfo.KeyChar); Console.Write(mask); } else if (keyInfo.Key == ConsoleKey.Backspace && sb.Length > 0) { sb.Remove(sb.Length - 1, 1); if (Console.CursorLeft == 0) { Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); Console.Write(' '); Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); } else Console.Write("\b \b"); } } Console.WriteLine(); return sb.ToString(); } 

Чтение ввода в консоль затруднено, вам нужно обрабатывать специальные клавиши, такие как Ctrl, Alt, также клавиши курсора и Backspace / Delete. На некоторых раскладках клавиатуры, таких как шведский Ctrl, требуется даже ввести ключи, которые существуют непосредственно на клавиатуре США. Я считаю, что попытка справиться с этим с помощью «низкоуровневого» Console.ReadKey(true) очень сложна, поэтому самый простой и самый надежный способ – просто отключить «входное эхо-сообщение» при вводе пароля, используя немного WINAPI ,

Нижеприведенный пример основан на ответе на « Чтение пароля» из вопроса std :: cin .

  private enum StdHandle { Input = -10, Output = -11, Error = -12, } private enum ConsoleMode { ENABLE_ECHO_INPUT = 4 } [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(StdHandle nStdHandle); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int lpMode); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetConsoleMode(IntPtr hConsoleHandle, int dwMode); public static string ReadPassword() { IntPtr stdInputHandle = GetStdHandle(StdHandle.Input); if (stdInputHandle == IntPtr.Zero) { throw new InvalidOperationException("No console input"); } int previousConsoleMode; if (!GetConsoleMode(stdInputHandle , out previousConsoleMode)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not get console mode."); } // disable console input echo if (!SetConsoleMode(stdInputHandle , previousConsoleMode & ~(int)ConsoleMode.ENABLE_ECHO_INPUT)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not disable console input echo."); } // just read the password using standard Console.ReadLine() string password = Console.ReadLine(); // reset console mode to previous if (!SetConsoleMode(stdInputHandle , previousConsoleMode)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not reset console mode."); } return password; } 

Это маскирует пароль с красным квадратом, а затем возвращается к исходным цветам после ввода пароля.

Это не мешает пользователю использовать копию / вставку, чтобы получить пароль, но если это больше подходит для того, чтобы остановить кого-то, смотрящего через плечо, это хорошее быстрое решение.

 Console.Write("Password "); ConsoleColor origBG = Console.BackgroundColor; // Store original values ConsoleColor origFG = Console.ForegroundColor; Console.BackgroundColor = ConsoleColor.Red; // Set the block colour (could be anything) Console.ForegroundColor = ConsoleColor.Red; string Password = Console.ReadLine(); // read the password Console.BackgroundColor= origBG; // revert back to original Console.ForegroundColor= origFG; 

Я обнаружил ошибку в решении srmy villa .NET C # 3.5 .NET, которое в противном случае работает в обаянии. Я также включил идею SecureString Дамиана Лещински – Ваша, но вы можете использовать обычную строку, если хотите.

BUG: Если вы нажмете backspace во время запроса пароля, а текущая длина пароля равна 0, звездочка неправильно вставлена ​​в маску пароля. Чтобы исправить эту ошибку, измените следующий метод.

  public static string ReadPassword(char mask) { const int ENTER = 13, BACKSP = 8, CTRLBACKSP = 127; int[] FILTERED = { 0, 27, 9, 10 /*, 32 space, if you care */ }; // const SecureString securePass = new SecureString(); char chr = (char)0; while ((chr = System.Console.ReadKey(true).KeyChar) != ENTER) { if (((chr == BACKSP) || (chr == CTRLBACKSP)) && (securePass.Length > 0)) { System.Console.Write("\b \b"); securePass.RemoveAt(securePass.Length - 1); } // Don't append * when length is 0 and backspace is selected else if (((chr == BACKSP) || (chr == CTRLBACKSP)) && (securePass.Length == 0)) { } // Don't append when a filtered char is detected else if (FILTERED.Count(x => chr == x) > 0) { } // Append and write * mask else { securePass.AppendChar(chr); System.Console.Write(mask); } } System.Console.WriteLine(); IntPtr ptr = new IntPtr(); ptr = Marshal.SecureStringToBSTR(securePass); string plainPass = Marshal.PtrToStringBSTR(ptr); Marshal.ZeroFreeBSTR(ptr); return plainPass; } 

Вы можете добавить свои ключи в накопительный связанный список.

Когда получен обратный ключ, удалите последний ключ из списка.

Когда вы получите ключ ввода, сверните свой список в строку и выполните оставшуюся часть своей работы.

Я сделал некоторые изменения для backspace

  string pass = ""; Console.Write("Enter your password: "); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // Backspace Should Not Work if (key.Key != ConsoleKey.Backspace) { pass += key.KeyChar; Console.Write("*"); } else { pass = pass.Remove(pass.Length - 1); Console.Write("\b \b"); } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); Console.WriteLine(); Console.WriteLine("The Password You entered is : " + pass); 

Я обновил версию Ронни, потратив слишком много времени, пытаясь ввести пароль, чтобы узнать, что у меня включен мой CAPS LOCK!

С этой версией, что сообщение в _CapsLockMessage будет «плавать» в конце области ввода и будет отображаться красным цветом.

Эта версия требует немного больше кода и требует цикла опроса. На моем компьютере использование ЦП составляет от 3% до 4%, но всегда можно добавить небольшое значение Sleep () для уменьшения использования ЦП, если это необходимо.

  private const string _CapsLockMessage = " CAPS LOCK"; ///  /// Like System.Console.ReadLine(), only with a mask. ///  /// a char representing your choice of console mask /// the string the user typed in public static string ReadLineMasked(char mask = '*') { // Taken from http://stackoverflow.com/a/19770778/486660 var consoleLine = new StringBuilder(); ConsoleKeyInfo keyInfo; bool isDone; bool isAlreadyLocked; bool isCapsLockOn; int cursorLeft; int cursorTop; ConsoleColor originalForegroundColor; isDone = false; isAlreadyLocked = Console.CapsLock; while (isDone == false) { isCapsLockOn = Console.CapsLock; if (isCapsLockOn != isAlreadyLocked) { if (isCapsLockOn) { cursorLeft = Console.CursorLeft; cursorTop = Console.CursorTop; originalForegroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.Write("{0}", _CapsLockMessage); Console.SetCursorPosition(cursorLeft, cursorTop); Console.ForegroundColor = originalForegroundColor; } else { cursorLeft = Console.CursorLeft; cursorTop = Console.CursorTop; Console.Write("{0}", string.Empty.PadRight(_CapsLockMessage.Length)); Console.SetCursorPosition(cursorLeft, cursorTop); } isAlreadyLocked = isCapsLockOn; } if (Console.KeyAvailable) { keyInfo = Console.ReadKey(intercept: true); if (keyInfo.Key == ConsoleKey.Enter) { isDone = true; continue; } if (!char.IsControl(keyInfo.KeyChar)) { consoleLine.Append(keyInfo.KeyChar); Console.Write(mask); } else if (keyInfo.Key == ConsoleKey.Backspace && consoleLine.Length > 0) { consoleLine.Remove(consoleLine.Length - 1, 1); if (Console.CursorLeft == 0) { Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); Console.Write(' '); Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); } else { Console.Write("\b \b"); } } if (isCapsLockOn) { cursorLeft = Console.CursorLeft; cursorTop = Console.CursorTop; originalForegroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.Write("{0}", _CapsLockMessage); Console.CursorLeft = cursorLeft; Console.CursorTop = cursorTop; Console.ForegroundColor = originalForegroundColor; } } } Console.WriteLine(); return consoleLine.ToString(); } 

Вот моя простая версия. Каждый раз, когда вы нажимаете клавишу, удаляете все из консоли и рисуете столько же «*», сколько длины строки пароля.

 int chr = 0; string pass = ""; const int ENTER = 13; const int BS = 8; do { chr = Console.ReadKey().KeyChar; Console.Clear(); //imediately clear the char you printed //if the char is not 'return' or 'backspace' add it to pass string if (chr != ENTER && chr != BS) pass += (char)chr; //if you hit backspace remove last char from pass string if (chr == BS) pass = pass.Remove(pass.Length-1, 1); for (int i = 0; i < pass.Length; i++) { Console.Write('*'); } } while (chr != ENTER); Console.Write("\n"); Console.Write(pass); Console.Read(); //just to see the pass 

Если я правильно понимаю это, вы пытаетесь сделать backspace удалять как видимый * символ на экране, так и кешированный символ в вашей переменной pass?

Если это так, то просто измените свой блок на это:

  else { Console.Write("\b"); pass = pass.Remove(pass.Length -1); } 
  string pass = ""; Console.WriteLine("Enter your password: "); ConsoleKeyInfo key; do { key = Console.ReadKey(true); if (key.Key != ConsoleKey.Backspace) { pass += key.KeyChar; Console.Write("*"); } else { Console.Write("\b \b"); char[] pas = pass.ToCharArray(); string temp = ""; for (int i = 0; i < pass.Length - 1; i++) { temp += pas[i]; } pass = temp; } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); Console.WriteLine(); Console.WriteLine("The Password You entered is : " + pass); 
Давайте будем гением компьютера.