Date: Tue, 28 Mar 2000 17:06:53 -0500 (EST) Subject: Re: [CGI] Crypt Problem On Mar 28, Anita Singh said: >I am facing a problem in encryption of my data. I have a a $variable. I >want to send the encrypted $variable value in an URL bcoz I don't want >users to see the value of the $variable. I can do it using crypt(). But I >don't know any function which works as "Anti-crypt"... I mean which >converts back the value of $variable in its original value. [Short answer] There is no method or function to un-crypt() a crypt()ed string. crypt() is a one-way hashing algorithm, meaning passwords are encrypted, and you can never find out what it used to be. Use some other method, such as UU-encoding: $encoded = pack "u", $string; # later... $regular = unpack "u", $encoded; [Long answer] crypt() takes an 8-character string (pads it with nulls, or truncates it, as needed) and performs some encryption on it. You are returned a 13- character string. Example: $password = "onomatopoeia"; $salt = "AZ"; $crypted = crypt $password, $salt; print $crypted; __END__ AZ8Rw/ax4qKe2 Hmm, so what good is that? I've encrypted data, but since it's a one-way operation, how do I get the data back? You don't. That's not what crypt is for. It's for encoding sensitive data so that you can compare other sensitive data with it, without having this data appear in plain text. Continuing on our example, let's look at something interesting: crypt "abcdefghij", "JP"; # JPUJfA.5yBNOI crypt "abcdefgh", "JP"; # JPUJfA.5yBNOI crypt "abcdefg", "JP"; # JPYKQI5Pyl7V6 Ah, the string is truncated to 8 characters, since we see that "abcdefgh" and "abcdefghi" crypt() to the same value. And when we get fewer than 8 characters, they're different. Let's examine this further: # \0 is the NULL character crypt "abcd", "JP"; # JP8Ol7CNzO9/s crypt "abcd\0\0", "JP"; # JP8Ol7CNzO9/s crypt "abcd\0\0\0\0", "JP"; # JP8Ol7CNzO9/s So we see that "jeff" and "jeff\0\0" would also crypt() to the same string, if given the same salt. What is that salt? It is a two character string, of the characters a-z, A-Z, 0-9, . and /. Do you notice how the first two characters of the string returned by crypt() are the salt? crypt "ABCDEFGH", "7/"; # 7/YQRsx6TolB. crypt "ABCDEFGH", "3d"; # 3dylmGBSqVqB2 crypt "ABCDEFGH", "fA"; # fAPrCZHd8Hw82 Also note that the salt is truncated to two characters. (It is not adviseable to use a salt of less than two characters, because the results are not definintely constant.) Let's take one of these crypt() result. fA PrCZHd8Hw82 |--|-----------| salt etcetera If crypt("ABCDEFGH","fA") is "fAPrCZHd8Hw82", then it should follow that crypt($guess, "fA") will also be "fAPrCZHd8Hw82" if $guess is the same string as "ABCDEFGH" (or if its first 8 characters are the same). So if you have a crypted string "fAPrCZHd8Hw82", and you want to see if a guess is the correct password, you can do this: if (crypt($guess, $crypted_string) eq $crypted_string) { # it's right! } This is because the crypted string is truncated to two characters, which is the salt used to get that string. You don't get the crypted string back to its original value -- it does not happen. Use some other encryption algorithm, one that can be reversed. A useful method is called One-Time Pass. It uses bit-wise XOR'ing of strings. #!/usr/bin/perl $str = "Once upon a time..."; $rand = rand_string(length($str)); $crypt = $str ^ $rand; $reg = $crypt ^ $rand; print "Message: $str\n"; print "Random: $rand\n"; print "Crypted: $crypt\n"; print "Restored: $reg\n"; sub rand_string { my $ret; for (1 .. $_[0]) { $ret .= chr(rand 256) } return $ret; } __END__ Message: Once upon a time... Random: [unprintables] Crypted: [more unprintables] Restored: Once upon a time... This takes advantage of a simple mathematical principle: (a XOR b) XOR b = a A random string of the same length as the message is generated. This is then XOR'ed, character-by-character, on the message. The result is "junk", but when you XOR this "junk" with the same random string, you get the original message back. The even nicer thing is that one, and ONLY one, random string will get you back what you started with. That means people trying to crack your program will have to guess 1 of 256 characters for EACH of the characters in your message. Thus, a message of 10 characters has 1 of 1208925819614629174706176 possible random strings associated with it. Think what happens when you get to larger messages. :)