Code:Passworteingabe in einer Win32Console
-
Hier gebe ich den code frei,um ein Passwort in einer Win32 Konsolenanwendung einzugeben, ohne dass es im Klartext dargestellt wird :
int ReadPassword(LPTSTR &szPassword,int &Length) { HANDLE m_STD_INPUT_HANDLE = GetStdHandle(STD_INPUT_HANDLE); HANDLE m_STD_OUTPUT_HANDLE = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwOldMode; GetConsoleMode(m_STD_INPUT_HANDLE,&dwOldMode); SetConsoleMode(m_STD_INPUT_HANDLE,0); char c; char PassChar = '*'; DWORD w; int i = 0; memset(szPassword,0,Length); do { if (i >= Length) break; if (!ReadConsole(m_STD_INPUT_HANDLE,&c,1,&w,NULL)) break; if ((c != '\n') && (c != '\r')) { i++; WriteConsole(m_STD_OUTPUT_HANDLE,&PassChar,1,&w,NULL); strncat(szPassword,(char*)&c,1); } } while ((c != '\n') && (c != '\r')); Length = strlen(szPassword); SetConsoleMode(m_STD_INPUT_HANDLE,dwOldMode); return 0; }
so benutzt man es:
Hier muss der Benutzer ein Passwort eingeben, dass mit Enter abgeschlossen wird.LPTSTR s = new char[100]; int l = 100; ReadPassword(s,l);
Eingabeparameter :
s ist ein allokierter String, der das Passwort aufnehmen soll
l ist ein Integer, der die maximale Eingabelänge angibt.
Wird diese überschritten, wird die Eingabe abgebrochen, als hätte der Benutzer Enter gedrückt.Ausgabeparameter
in "s" steht das Passwort (ohne abschließende 0)
in l steht die Anzahl der gelesenen Zeichen (ohne Eingabetaste)Der Rückgabewert ist immer 0 (für mögliche Fehler der WinAPI reserviert)
Bugs usw bitte hier posten!
Übrigens musst du diesen Code auf eigene Verantwortung benutzen.
Ich übernehme keinerlei Verantwortung für den Code!!
Der Code ist FREI für FREE und COMERZ!Viel Spass beim Programmieren
-
Irgendwer hat mal gesagt man soll nur so tief Low-Level gehen wie unbedingt nötig. Deswegen:
#include <iostream> #include <string> #include <conio.h> std::string read_pw ( unsigned short int Maxlength , char Ersatz = '*' ) { std::string pw; char now ( '\0' ); while ( ( Maxlength-- > 0 ) && ( now != 13 ) && ( now != 10 ) ) { /* Zeichen einlesen */ now = getch (); /* Bei Sonderzeichen zweites Zeichen ignorieren */ if ( now == 0 || now == 0x0E ) { getch (); } /* Backspace abfangen */ else if ( now == 8 ) { pw.erase ( pw.end() - 1 , 1 ); cout << "\b \b"; } /* Wenn Zeichen normal dann an das Passwort anhängen */ else { pw = pw + now; cout << Ersatz; } } return ( pw ); }
Sollte funktionieren.
Edit: now initialisiert und 224 durch 0x0E ausgetauscht.
MfG SideWinder
-
@SideWinder
Warum einfach, wenns kompliziert auch geht...char now ( '\0' ); => char now=0;
Frage:
pw := pw + now;Ist das nicht ne Zuweisung im Pascal?? Also in C hab ich sowas noch nicht gesehen.
Und warum schreibst du einmal dezimal und dann hexadezimal??
-
AJ schrieb:
@SideWinder
Warum einfach, wenns kompliziert auch geht...char now ( '\0' ); => char now=0;
Frage:
pw := pw + now;Ist das nicht ne Zuweisung im Pascal?? Also in C hab ich sowas noch nicht gesehen.
Und warum schreibst du einmal dezimal und dann hexadezimal??
1. Weil ich nunmal auch char fuer eine Klasse halte und es richtig initialisieren will ;). Glaub das ist reine Formsache aber irgendwer hat mal gesagt man soll meine Version nehmen.
2. Ja. Gottverdammtes TP :D. Naja, geändert ;).
3. Weil in der FAQ 0xE0 steht - dann ist das leichter nachvollziehbar.
MfG SideWinder
-
1. Ok dann hald als Klasse:
char now (0);3. Das erklärt immer noch nicht folgendes:
while ( ( Maxlength-- > 0 ) && ( now != 13 ) && ( now != 10 ) ) //rein Dezimal
if ( now == 0 || now == 0x0E ) //und hier Hexadezimal
Vom Ablauf her ists zwar egal, aber beim Lesen könnte es doch etwas verwirren, nicht wahr?
-
super dass sich soviele beteiligen
übrigens:
mittlerweile habe ich eine verbesserte Version gebaut.
Allerdings werde ich diese erst mit einer größeren Toolssammlung auf sourceforge.net ausstellen, wenn ich soweit bin.
Darunter :
VString (Stringhandling like MFC und besser)
- pw = pw + now; ist dann möglich
VConsole (Konsolenprogrammierung mit Klassen)
- ReadLine kennt die Standardfunktionen eines Editfeldes
VDialog (WinAPI in Klassen gekapselt)
-
@AJ:
1. Ein char wird bei mir zuerst mit einer Konstante dann mit einer Escapesequenz und nur wenn nicht anders möglich mit einer Zahl initialisiert.
3. Hexadezimale Zahl nur weil in der FAQ und auch in der MSDN 0xE0 steht statt 224. Was ich allerdings nicht weiß warum ich 10 und 13 nicht mit '/r' und '/n' definiert habe - naja seis drum, kann man ja noch ändern ;).
@Dezipiator: VString hat für mich irgendwie keinen Sinn, im Grunde erfindest du nur das Rad neu. Wenn du schon noch ein paar Zusatzfunktionen bieten willst erbe doch von std::string public und füge noch etwas dazu. Aber es gibt schon soviele Stringklassen das eine mehr fast nichts mehr bringt.
Readline klingt schon ganz gut. Ich persönlich will immer noch eine getch-Streamklasse erstellen die für die einzelnen Typen überladen ist. Wenn ich zB getch auf einen Integer anwende kommt das FAQ-Beispiel "Reine Zahleneingabe" zur Geltung. Wenn ich einen char nehme kann man nur Zeichen eingeben (eventl. auch mit einem Flag welche genau also zB A-Za-z0-9() also so eine Art Zeichenklassen wie man sie von den Regex-Funktionen kennt).
VDialog klingt mir ziemlich nach MFC?! Was genau soll da wie gekapselt werden?
MfG SideWinder
-
@Side
Dann hast du da wohl noch einen Fehler in deinem Quellcode. Soll das jetzt 0x0E sein oder 0xE0???
-
ka das kann ich mir nie merken - *auch in die FAQ schau* 0x0E passt schon.
MfG SideWinder
-
VString bietet meist das ,was oft zum Problem wird.
Automatische Typenumwandlung.
Außerdem werden viele Operatoren überladen, die doch das Leben z.b. bei cin und cout sehr vereinfachen :hier die definition:
http://spotlight.de/zforen/cpp/m/cpp-1060116715-15802.htmlVDialog ist eigentlich nur dazu gedacht,
schnell ein Dialog zu erstellen, und auf Nachrichten zu reagieren.
Man muss dazu nicht VDialog überschreiben, sondern ein EventHandler Objekt, dass dann dem Dialog übergeben wird.
Man muss sich nicht mit der Winapi beschäftigen.Außerdem hat das alles einen großen Vorteil :
Es ist klein und kommt ohne jegliche DLLs aus!
-
Ich habe mal ein wenig korrigiert, damit die Fehlermeldungen aufhören und das überhaupt geht. So schluckt das auch der Dev-C++:
#include <iostream> #include <string> #include <conio.h> using namespace std; string read_password ( int maxlength ) { string pw ( "" ); char now ( '\0' ); while ( ( maxlength-- > -1 ) && ( now != 13 ) && ( now != 10 ) ) { // Zeichen einlesen now = getch (); // Bei Sonderzeichen zweites Zeichen ignorieren if ( now == 0 || now == 0xE0 ) // 0xE0 = 224 { getch (); } // Backspace abfangen else if ( now == '\b' ) { pw.erase ( pw.end()-1 ); cout << "\b \b"; maxlength+=2; } // Wenn Zeichen normal dann an das Passwort anhängen if( (now == 13) || (now == 8) ) { } else { pw = pw + now; cout << '*'; } } return ( pw ); } int main() { cout << "Passwort eingeben: "; string pw = read_password(5); if (pw == "Hal?o") cout << "\no.k." << endl; else cout << "\nfalsches Passwort" << endl; getch(); }
Ist aber noch nicht völlig in Ordnung, z.B. Backspaces über Anfang hinaus, kann man aber mit leben.
-
Hallo ! der code is super nur kann man nicht die BACKSPACE taste benützen.. also man kann es schon und er reagiert auch auf dei BACKSPACE taste nur zeig er das nicht an .. er zeigt noch eine gedrückte taste an.
Bsp.:
ich gebe ein abcd[BACKSPACE]
BILDSCHIRM: ***** //er macht noch ein Stern für BACKSPACE statt eins zu löschen
Aber wenn ich das PW ausgebe kommt das richtige raus:
BILDSCHIRM: abckannst du bitte den code noch so verbessern das er ein sternchen löscht statt eins dazu zu machen .... pls.! DANKE!
-
Also meine nachricht war an Dezipaitor und gemeint habe ich den CODE den er ganz am Anfang geschrieben hat!
-
Warum nimmst Du nicht den einfacheren Code?
-
ich finde, bei den vielen passwortfragen könnte dezipaitors code in die faq für konsole mit winapi möglichkeit (windows.h) und für die dos und djgpp leute kann was daneben gestellt werden.
-
So, hier meine Version für ANSI-C
char *read_password(char *password, int maxlength, char passchar) { char *pos=password; char now=0; //Solange die Taste Return nicht gedrückt wurde //und solange die maximale Anzahl an Zeichen nicht erreicht wurde while(now!=13 && now!=10 && pos-password<maxlength) { // Zeichen einlesen now=getch(); // Bei Sondertaste zweites Zeichen ignorieren if(now==0 || now==0xE0) // 0xE0 = 224 { getch(); continue; // Nächstes Zeichen einlesen } else if(now==8) //Wenn Backspace gedrückt wurde { if(pos>password) //Nur wenn schon ein Zeichen da ist! { *--pos=0; //Zuletzt eingegebenes Zeichen löschen printf("\b \b"); //Bildschirmausgabe korrigieren } } // Wenn eingelesenes Zeichen kein Steuerzeichen ist if(now>31) { *pos++=now; //Zeichen speichern putch(passchar); //Passwortzeichen ausgeben } } return(password); //Passwort zurückgeben }
Edit: Schönheitskorrekturen
-
Hey AJ supa cool bitte schreib auch eine main dazu wie man die Fkt. aufruft bitte!!!! -> Bin Anfänger! DANKE!
-
Das Backspace war garnicht vorgesehen.
Deshalb hier die Erweiterte Variante.
Allerdings funktioniert das Backspace nicht über das horizontale Zeilenende hinaus. Sobald der Cursor darüber hinaus geht, kann er nicht mehr zurück (der interne Zeichenpuffer wird trotzdem geändert)
Außerdem wird jetzt nicht mehr abgebrochen, wenn die maximale Anzahl von Zeichen erreicht wurde - in diesem Fall kann man einfach nicht mehr weiterschreiben -> Backspace geht allerdings schonCode
siehe weiter untenSobald ich es mal geschafft habe bei Sourceforge.net einen Account zu eröffnen.
Lade ich die erweiterte Konsolenklasse hoch
-
hi! @Dezipaitor
Du hast am anfang des codes etwas vergessen:HANDLE m_STD_INPUT_HANDLE = GetStdHandle(STD_INPUT_HANDLE); HANDLE m_STD_OUTPUT_HANDLE = GetStdHandle(STD_OUTPUT_HANDLE);
Aber sonst Funktionier alles einwandfrei! echt toll danke man!
-
@elise: Jetzt lass den Thread doch erstmal reifen :p
Standard C++ Variante:
@Erhard Henkes: Niemals Namespaces in eigenen Headern öffnen! Außerdem ist -1 ein Fehler gibt er 0 an wird die Schleife trotzdem einmal ausgeführt!
#include <iostream> #include <string> #include <conio.h> std::string read_pw ( unsigned short int Maxlength , char Ersatz = '*' ) { std::string pw ( "" ); char now ( '\0' ); while ( ( Maxlength-- > 0 ) && ( now != 13 ) && ( now != 10 ) ) { /* Zeichen einlesen */ now = getch (); /* Bei Sonderzeichen zweites Zeichen ignorieren */ if ( now == 0 || now == 0xE0 ) { getch (); } /* Backspace abfangen */ else if ( now == 8 ) { /* Wenn bereits Zeichen im String vorhanden sind */ if ( pw.length () = 0 ) { pw.erase ( pw.end() - 1 ); cout << "\b \b"; Maxlength += 2; } } /* Wenn Zeichen normal dann an das Passwort anhängen */ else if ( now != 13 ) { pw = pw + now; cout << Ersatz; } } return ( pw ); }
So final herausgebracht.
MfG SideWinder