1. prompt_password()
- Posted by ghaberek (admin) Jun 29, 2012
- 1411 views
I had a need to prompt the user for a password on the console, and I was surprised to see that we didn't have this in the standard library already.
Can and/or should this be added?
public function prompt_password( sequence prompt = "Password: " ) -- prompt the user for some text, but do not display the characters sequence answer = "" puts( 1, prompt ) atom key = wait_key() while key != 13 do -- exit on return if key = 8 and length( answer ) then -- backspace answer = answer[1..$-1] elsif key > 31 and key < 255 then -- printable character answer &= key end if key = wait_key() end while puts( 1, "\n" ) return answer end function
-Greg
2. Re: prompt_password()
- Posted by jimcbrown (admin) Jun 29, 2012
- 1401 views
My 2 cents - I'm in favor.
I had a need to prompt the user for a password on the console, and I was surprised to see that we didn't have this in the standard library already.
Can and/or should this be added?
public function prompt_password( sequence prompt = "Password: " ) -- prompt the user for some text, but do not display the characters sequence answer = "" puts( 1, prompt ) atom key = wait_key() while key != 13 do -- exit on return if key = 8 and length( answer ) then -- backspace answer = answer[1..$-1] elsif key > 31 and key < 255 then -- printable character answer &= key end if key = wait_key() end while puts( 1, "\n" ) return answer end function
-Greg
3. Re: prompt_password()
- Posted by tbohon Jun 29, 2012
- 1372 views
I too think it's a good idea but maybe we should incorporate display of an asterisk ( * ) for each character typed? That will at least give the user some idea that things are happening and might save them from a erroneous password if, for example, their password is 6 characters but 5 * show on the screen.
Just my 2c worth ... your mileage DEFINITELY will vary. :)
4. Re: prompt_password()
- Posted by jimcbrown (admin) Jun 29, 2012
- 1380 views
I too think it's a good idea but maybe we should incorporate display of an asterisk ( * ) for each character typed? That will at least give the user some idea that things are happening and might save them from a erroneous password if, for example, their password is 6 characters but 5 * show on the screen.
Just my 2c worth ... your mileage DEFINITELY will vary. :)
I agree ... maybe an optional string, defaulting to "*" , but allowing the application writer to decide what character makes sense.
In some cases, that string will be empty. Other tools, like SSH, do not show you how many characters you have typed for your password. This is simply a trade-off between ease-of-use and security.
5. Re: prompt_password()
- Posted by DerekParnell (admin) Jun 29, 2012
- 1396 views
Can and/or should this be added?
I agree in principle, but we should have one that is more secure than this. I'll work on one later today and post it for inspection.
6. Re: prompt_password()
- Posted by DerekParnell (admin) Jun 30, 2012
- 1494 views
I'll work on one later today and post it for inspection.
And here it is ...
include std/graphics.e include std/math.e /* Returns an encoded password based on the user's input. The actual password itself is not returned so the value returned by this function is safe to store because even if viewed, the original password cannot be determined. Note that even passwords that are textually similar will produce extremely different encoded values. The returned value is a sequence of bytes. The number of bytes returned is determined by the 'pwsize' parameter. By default this is 28. Regardless of the actual size of the user's password, this function will always return 'pwsize' number of bytes. Note that the minimum 'pwsize' is 8. As the user presses usable keys, the 'dispsym' parameter (a character) is displayed for each keypress. By default this is the '*' character. If 'dispsym' is less than 1, no character displaying will occur. When displaying characters, at most 'maxdisp' characters will be displayed, regardless of how many characters are in the actual password. By default this is set to 10. This allows users to have longer passwords than the screen area would otherwise accommodate. The 'quality' parameter, if set to a non-zero value, will cause return value to consist of two sequences. The first element is the encoded password, and the second is a representation of the types of characters keyed by the user. There will be one atom value per character entered. The floor() of this value will be from 1 to 5, indicating the class of character. 1 = Lowercase alphabetic 2 = Uppercase alphabetic 3 = Digit 4 = Punctuation 5 = Non-displayable character (e.g. The ESCAPE and Ctrl-X characters) If a value is not an integer, then the non-integer portion can be made up of any combination (addition) of 0.4, 0.2, 0.1, and 0.05. 0.4 = 'alphabetically' adjacent to the previous key (eg. 'a' and 'b') 0.2 = 'horizontally' adjacent to the previous key (eg. 'a' and 's') 0.1 = 'vertically' adjacent to the previous key (eg. 'a' and 'z') 0.05 = Duplicate of previous key. Examples: -- 'e' followed by 'd', would give a value for 'd' of 1.5, because 'd' is lowercase and is alphabetically and vertically adjacent to 'e'. -- 'M' followed by 'N', would give a value for 'N' of 2.6, because 'N' is uppercase and is alphabetically and horizontally adjacent to 'M'. The caller can uses this information to determine an assessment of the quality of the password supplied by the user. By default, the quality information is not returned. */ public function prompt_password( sequence prompt = "Password: ", integer pwsize = 28, integer dispsym = '*', integer maxdisp = 10, integer quality = 0 ) sequence pos sequence encodedpw = "" sequence qkeys = "" integer key integer pnkey = -1 integer pkkey = -1 integer pdkey = -1 if pwsize < 8 then pwsize = 8 end if puts( 1, prompt ) if dispsym > 0 then pos = get_position() end if while key != 13 with entry do if key <= 255 then -- Ignore navigation keys etc ... if key = 8 then -- backspace if length(encodedpw) > 0 then -- Remove last character keyed. encodedpw = encodedpw[1..$-1] if quality then qkeys = qkeys[1 .. $-1] end if if dispsym > 0 then -- Fix up screen display. pos[2] -= 1 position(pos[1], pos[2]) puts(1, ' ') position(pos[1], pos[2]) end if end if else -- new character -- Get a hash value based on both the new character and all -- the previous characters, but only use the least significant -- byte value of the result. Append this to the encoded string. encodedpw &= and_bits(#FF, hash(key, key & encodedpw)) if quality then -- Ok, quality data was requested for this. integer nkey, kkey nkey = find(key, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_-+={[}]|\\;:'\",<.>/?") if nkey = 0 then nkey = key + 94 end if if nkey <= 26 then qkeys &= 1 -- lowercase elsif nkey <= 52 then qkeys &= 2 -- uppercase elsif nkey <= 62 then qkeys &= 3 -- digit elsif nkey <= 94 then qkeys &= 4 -- punctuation else qkeys &= 5 -- non-displayable end if if nkey = pnkey then -- Duplicate keys qkeys[$] += 0.05 end if if abs(nkey - pnkey) = 1 then -- 'alphabetically' adjacent qkeys[$] += 0.4 end if pnkey = nkey -- Check horizontal proximity kkey = find(key, "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?" & {17,23,5,18,20,25,21,9,15,16,27,29,28,-1,1,19,4,6,7,8,10,11,12,-1,26,24,3,22,2,14,13}) if kkey = 0 then kkey = key + 94 end if if abs(kkey - pkkey) = 1 then -- Horizontally adjacent qkeys[$] += 0.2 end if pkkey = kkey -- Check vertical proximity kkey = find(key, "`1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik,9ol.0p;/-['=]\\~!QAZ@WSX#EDC$RFV%TGB^YHN&UJM*IK<(OL>)P:?_{\"+}|"& {17,1,26,-1,19,24,23,-1,5,4,3,-1,18,6,22,-1,20,7,2,-1,25,8,14,-1,21,10,13,-1,9,15,-1,11,16,-1,12}) if kkey = 0 then kkey = key + 94 end if if abs(kkey - pdkey) = 1 then -- Vertically adjacent qkeys[$] += 0.1 end if pdkey = kkey else key = 0 end if if dispsym > 0 then -- Got to display something. position(pos[1], pos[2]) puts(1, dispsym) if length(encodedpw) < maxdisp then pos[2] += 1 end if end if end if end if entry key = wait_key() end while if length(encodedpw) > 0 then -- Ok, I got something from the user, so I need to -- make sure its long enough and churned enough to -- make it hard to work backwards to the actual -- password. encodedpw = append(prepend(encodedpw, length(encodedpw)), pwsize) loop do encodedpw &= encodedpw for i = 1 to length(encodedpw) do encodedpw[i] = hash(encodedpw[$-i+1], encodedpw) end for encodedpw = and_bits(#FF, encodedpw) until length(encodedpw) > pwsize end loop -- Just take from the righthand part of the encoded string. encodedpw = encodedpw[$ - pwsize .. $ - 1] end if if quality then return {encodedpw, qkeys} else return encodedpw end if end function
Using this function with the default settings, a password of "password" encodes as
{215,177,114,108,140,170,165,109,80,182,144,175,243,161,118,186,40,182,218,51,89,228,191,112,111,2,174,87}
and a password of "Password" encodes as
{159,107,83,106,92,120,183,62,157,229,128,11,34,183,168,237,41,177,124,52,117,219,31,157,146,218,206,3}which is not exactly guessable or simple to reverse engineer.
No doubt this function can be further improved.
Forked into: Password hashing // lack of cryptographic hash functions
7. Re: prompt_password()
- Posted by jimcbrown2 (admin) Jun 30, 2012
- 1346 views
I'll work on one later today and post it for inspection.
And here it is ...
include std/graphics.e include std/math.e /* Returns an encoded password based on the user's input. The actual password itself is not returned so the value returned by this function is safe to store because even if viewed, the original */
While I like this idea along with other features of this function (like the concept of having a password quality checker, or the ability to compress the display chars so the user can type in an extra-long password or pass phrase), I don't think this the right place to deal with hashing the password.
In many cases, the application ask the user for the password, then pass it on to another (e.g. telnet, FTP, HTTP basic AUTH). In other cases, the application will have to hash or encrypt the raw value of the password in a certain way and then pass that hash on (e.g. SSH, HTTP Digest AUTH) and if prompt_password is returning the password with the wrong hash, then that's the end of that. The inability of this function to accommodate that makes it of significantly limited utility imvho.
While I like the idea of the quality checker, I think the implementation is quite raw. There's no simple length checking (though this can be determined by the other information returned by the quality checker), and there's no protection against using dictionary words or too common passwords ala cracklib.
8. Re: prompt_password()
- Posted by mattlewis (admin) Jun 30, 2012
- 1337 views
While I like this idea along with other features of this function (like the concept of having a password quality checker, or the ability to compress the display chars so the user can type in an extra-long password or pass phrase), I don't think this the right place to deal with hashing the password.
Yes, I think these things should be split out as separate functions. Is there enough here to justify a separate include file?
Matt
9. Re: prompt_password()
- Posted by jimcbrown (admin) Jun 30, 2012
- 1330 views
While I like this idea along with other features of this function (like the concept of having a password quality checker, or the ability to compress the display chars so the user can type in an extra-long password or pass phrase), I don't think this the right place to deal with hashing the password.
Yes, I think these things should be split out as separate functions. Is there enough here to justify a separate include file?
Matt
I feel that there is. Actually, we've always been weak on the security / crypto side of things.
10. Re: prompt_password()
- Posted by DerekParnell (admin) Jun 30, 2012
- 1306 views
Ok, if one is collecting a password on behalf of another application, then all bets are off. The system is innately insecure in that situation.
An unsecure, dumbed-down version could more like this ...
include std/graphics.e /* Returns the user's input. The returned value is a sequence of bytes. As the user presses usable keys, the 'dispsym' parameter (a character) is displayed for each keypress. By default this is the '*' character. If 'dispsym' is less than 1, no character displaying will occur. When displaying characters, at most 'maxdisp' characters will be displayed, regardless of how many characters are in the actual password. By default this is set to 10. This allows users to have longer passwords than the screen area would otherwise accommodate. */ public function prompt_password( sequence prompt = "Password: ", integer dispsym = '*', integer maxdisp = 10 ) sequence pos sequence user_input = "" integer key puts( 1, prompt ) if dispsym > 0 then pos = get_position() end if while key != 13 with entry do if key <= 255 then -- Ignore navigation keys etc ... if key = 8 then -- backspace if length(user_input) > 0 then -- Remove last character keyed. user_input = user_input[1..$-1] if dispsym > 0 then -- Fix up screen display. pos[2] -= 1 position(pos[1], pos[2]) puts(1, ' ') position(pos[1], pos[2]) end if end if else -- new character user_input &= key if dispsym > 0 then -- Got to display something. position(pos[1], pos[2]) puts(1, dispsym) if length(user_input) < maxdisp then pos[2] += 1 end if end if end if end if entry key = wait_key() end while return user_input end function
11. Re: prompt_password()
- Posted by ghaberek (admin) Jul 01, 2012
- 1278 views
Derek,
dispsym should be >= 32, since ASCII values 0-31 are non-printable.
-Greg
12. Re: prompt_password()
- Posted by DerekParnell (admin) Jul 01, 2012
- 1270 views
Derek,
dispsym should be >= 32, since ASCII values 0-31 are non-printable.
-Greg
Who says they have to be printable? I'm pretty sure that characters 1 to 31 have displayable glyphs in Windows and Unix terminals.
13. Re: prompt_password()
- Posted by ghaberek (admin) Jul 01, 2012
- 1244 views
Who says they have to be printable? I'm pretty sure that characters 1 to 31 have displayable glyphs in Windows and Unix terminals.
Well, I think it's generally understood that passwords should be only valid alphanumeric (or extended/accented) characters.
I don't think TAB or ESC should be valid password characters. And it's impossible to enter BEL or ACK on a keyboard.
Just my 2¢.
-Greg
14. Re: prompt_password()
- Posted by DerekParnell (admin) Jul 01, 2012
- 1251 views
Who says they have to be printable? I'm pretty sure that characters 1 to 31 have displayable glyphs in Windows and Unix terminals.
Well, I think it's generally understood that passwords should be only valid alphanumeric (or extended/accented) characters.
I don't think TAB or ESC should be valid password characters. And it's impossible to enter BEL or ACK on a keyboard.
Just my 2¢.
-Greg
The dispsym is the character displayed on the screen and has nothing to do with the characters contained in the password.
Some unix systems even allow the BACKSPACE character as a valid password character.
BEL is Ctrl-G and ACK is CTRL-F.
15. Re: prompt_password()
- Posted by AndyDrummond Jul 02, 2012
- 1226 views
The thread above is fine, but may I add another idea I use for my password system?
It is simply to display a random lower-case alpha for each character typed rather than an asterisk. The only reason for asterisks is to hide the password from a snooper; if random letters are shown the snooper will immediately see those and think they are the password, and so not look at the keyboard being used, or, if looked at at a later date, the snooper will assume that the alphas MUST be right or at least close to the truth. Which is, of course, as far from the truth as you can get.
This is of course dead simple to implement.
16. Re: prompt_password()
- Posted by wynco Jul 03, 2012
- 1273 views
The encryption program I am writing is a windows program, so I don't if it applies directly to this discussion.
The way I am handling passwords is to use normal EditText fields and intercept the keys as they are typed.
The program has a number of Ctrl and Alt hot keys, so I did not want to use any modified characters in the passwords. This limited the number of characters that could be entered to approximatly 95 from a standard windows keyboard. This was not acceptable, so what I done was added a toggle to turn ON/OFF an extended character set using Ctrl+E or by a popup menu. When extended characters is on, I remap characters from 32 to 127 to two different groups in the 128 to 255 range, so typing 'a' with extended on enters a keycode 227 and 'A' enters 159 and so on. This allows 190 characters using only the normal 'typewriter' type keys.
There is also a Hide/Show characters toggle (Ctrl+*) to show the actual characters typed or show all asterisks. 'Show characters' can be toggled off whether the fields are empty or not, however it cannot not be toggled on unless both password fields are empty.
The fields allow 1 to 32 character passwords, I don't want to police minimum password lengths, so I leave it up to the user to enter secure passwords.
All passwords are expanded to 32 characters during the encryption process.
More to the point, how about expanding the dispsym flag to display either astericks or random characters, such as
integer dispsym = "*" for astericks or
integer dispsym = "r" for random, as Andy suggested
and another flag to return the raw characters typed or a more secure encoded password, such as
integer dispsym = "r" for raw or
integer dispsym = "e" for encoded as Derek suggested
17. Re: prompt_password()
- Posted by wynco Jul 03, 2012
- 1202 views
Slight correction, the return flag would be something like returnchars not dispsym