Приложение для маскировки паролей
Я пробовал следующий код...
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 не работает при вводе пароля.
Любое предложение?
Ответы
Ответ 1
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");
}
}
Ответ 2
Для этого вы должны использовать 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
{
pwd.AppendChar(i.KeyChar);
Console.Write("*");
}
}
return pwd;
}
Ответ 3
Полное решение, vanilla С#.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<Password>{0}</Password>", password);
Console.ReadLine();
}
}
}
namespace Orb.App
{
/// <summary>
/// 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.
/// </summary>
static public class Console
{
/// <summary>
/// Like System.Console.ReadLine(), only with a mask.
/// </summary>
/// <param name="mask">a <c>char</c> representing your choice of console mask</param>
/// <returns>the string the user typed in </returns>
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>();
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());
}
/// <summary>
/// Like System.Console.ReadLine(), only with a mask.
/// </summary>
/// <returns>the string the user typed in </returns>
public static string ReadPassword()
{
return Orb.App.Console.ReadPassword('*');
}
}
}
Ответ 4
Mine игнорирует управляющие символы и обрабатывает перенос строк:
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();
}
Ответ 5
Взяв верхний ответ, а также предложения от его комментариев и изменив его использование 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;
}
Ответ 6
Чтение ввода в консоли затруднено, вам нужно обрабатывать специальные клавиши, такие как 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;
}
Ответ 7
Я нашел ошибку в решении shermy vanilla С# 3.5.NET, которое в противном случае срабатывает. Я также включил идею Damian Leszczyński - Vash SecureString, но вы можете использовать обычную строку, если хотите.
THE 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;
}
Ответ 8
Вы можете добавить свои ключи в накопительный связанный список.
Когда получен обратный ключ, удалите последний ключ из списка.
Когда вы получаете ключ ввода, сверните свой список в строку и выполните оставшуюся часть своей работы.
Ответ 9
Я сделал некоторые изменения для 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);
Ответ 10
Я обновил версию Ronnie, потратив слишком много времени, пытаясь ввести пароль только, чтобы узнать, что у меня включен мой CAPS LOCK!
В этой версии сообщение, которое когда-либо было в _CapsLockMessage
, будет "плавать" в конце области ввода и будет отображаться красным цветом.
Эта версия требует немного больше кода и требует цикла опроса. На моем компьютере использование ЦП составляет от 3% до 4%, но всегда можно добавить небольшое значение Sleep(), чтобы уменьшить использование ЦП, если это необходимо.
private const string _CapsLockMessage = " CAPS LOCK";
/// <summary>
/// Like System.Console.ReadLine(), only with a mask.
/// </summary>
/// <param name="mask">a <c>char</c> representing your choice of console mask</param>
/// <returns>the string the user typed in</returns>
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();
}
Ответ 11
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);
Ответ 12
Это маскирует пароль с красным квадратом, а затем возвращается к исходным цветам после ввода пароля.
Это не мешает пользователю использовать копию/вставку, чтобы получить пароль, но если это больше подходит для остановки кого-то, смотрящего через плечо, это хорошее быстрое решение.
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;
Ответ 13
Если я правильно понимаю это, вы пытаетесь сделать backspace удалять как видимый * символ на экране, так и кешированный символ в вашей переменной pass?
Если это так, то просто измените блок else на это:
else
{
Console.Write("\b");
pass = pass.Remove(pass.Length -1);
}