[c#] パスワードマスキングコンソールアプリケーション



Answers

このためには、 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;
}
Question

私は次のコードを試した...

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);

しかし、パスワードを入力している間、バックスペース機能は動作しません。 なにか提案を?




コンソール入力を読むのは難しいですが、Ctrl、Alt、カーソルキー、Backspace / Deleteなどの特別なキーを処理する必要があります。 一部のキーボードレイアウトでは、 Swedish 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;



ここに私の簡単なバージョンがあります。 キーを押すたびに、コンソールからすべてを削除し、パスワード文字列の長さと同じ数の '*'を描画します。

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



        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);



一番上の答えとそのコメントから、Stringの代わりにSecureStringを使用するように修正し、すべてのコントロールキーをテストし、エラーではなく、パスワードの長さが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;
}



バックスペースにいくつか変更を加えました

        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);



Related