Re: prompt_password()
- Posted by DerekParnell (admin) Jun 30, 2012
- 1494 views
DerekParnell said...
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