PFMaBiSmAd Posted June 27, 2008 Share Posted June 27, 2008 First of all, two-way encryption/decryption is not the same as a one-way hash. Getting this to work is not a matter of finding the right class or right code it is a matter of finding why your code and data is not working. I created a database with a blob column and tested your class code and it works. So, something that php is doing (such as the magic_quotes_runtime setting adding escape characters to the data when it comes out of the database) or something your code is doing is causing the problem. For all we know, your code is doing an md5 on the data (since some of this seems to be left over from a password function.) We really need to see your code to be able to help. Have you echoed out the various values to make sure of what they contain and have you compared these with what is in the database? Does the string you get out of the database have \ in it before several of the characters? The string you insert into the database, the string in the database, and the string you select out of the database should all be identical. The class code you posted has a rtrim() in the decrypt function left over from when it was a password function. I recommend removing that (it would have no effect on a true CC number unless there were trailing trim-able characters, which your validation code should have dealt with long before they were encrypted.) The code Jabop posted has an additional trim() function added to the encoding. This can break the process because there could be leading and trailing trim-able characters. Quote Link to comment Share on other sites More sharing options...
Jabop Posted June 27, 2008 Share Posted June 27, 2008 This is just plain ugly, and quite redundant. Simply using a random salt, and randomly mixing it in with a hash is more than enough to make it unfeasible to brute-force, and also protects it from any existing table-based attacks. That will be really hard to return the CC numbers at all when you do that - and I think he needs to store the numbers for records. It'd be easier to just encrypt the numbers and decrypt them when needed Quote Link to comment Share on other sites More sharing options...
Jabop Posted June 27, 2008 Share Posted June 27, 2008 The code Jabop posted as an additional trim() function added to the encoding. This can break the process because there could be leading and trailing trim-able characters. Why would you use whitespace in a credit card number? Quote Link to comment Share on other sites More sharing options...
PFMaBiSmAd Posted June 27, 2008 Share Posted June 27, 2008 You are trimming the encrypted output where it is being returned to the calling function. Edit: The encrypted output can contain any 0-255 value. Trim removes several of these values - " " (ASCII 32 (0x20)), an ordinary space. "\t" (ASCII 9 (0x09)), a tab. "\n" (ASCII 10 (0x0A)), a new line (line feed). "\r" (ASCII 13 (0x0D)), a carriage return. "\0" (ASCII 0 (0x00)), the NUL-byte. "\x0B" (ASCII 11 (0x0B)), a vertical tab. Quote Link to comment Share on other sites More sharing options...
Jabop Posted June 27, 2008 Share Posted June 27, 2008 Right, that is what trim does. In a credit card number, only numbers are allowed (obv), so I put trim in there for his sake. Quote Link to comment Share on other sites More sharing options...
br0ken Posted June 27, 2008 Author Share Posted June 27, 2008 Here is the code I've been using to test the encryption functions. First I select the credit card number (cnumber) and then encrypt it and then decrypt it. These values are stored in cnumbenc and cnumbdec. After this has been done for all of the numbers I display the resulting table. The commented out line loads the encrypted value from the database, decrypts it then stores it in cnumbenc. $db = openDB(); $rs = queryDB("SELECT id, cnumber FROM tblCard LIMIT 100"); $row = 0; while(getrowRS($rs)) { $id = getvalueRS($rs, $row, "id"); $card = getvalueRS($rs, $row, "cnumber"); $enc = xEncrypt($card, mykey()); $dec = xDecrypt($enc, mykey()); queryDB("UPDATE tblCard SET cnumbenc = '".mysql_real_escape_string($enc)."', cnumbdec = '".mysql_real_escape_string($dec)."' WHERE id = $id"); # $dec = xDecrypt(queryDBval("SELECT cnumbenc FROM tblCard WHERE id = $id"), mykey()); # queryDB("UPDATE tblCard SET cnumbdec = '".input($dec, 60)."' WHERE id = $id"); ++$row; } printRS(queryDB("SELECT id, cnumber, cnumbenc, cnumbdec FROM tblCard LIMIT 100")); Quote Link to comment Share on other sites More sharing options...
discomatt Posted June 27, 2008 Share Posted June 27, 2008 Right, that is what trim does. In a credit card number, only numbers are allowed (obv), so I put trim in there for his sake. Yes but you're trimming the ENCRYPTED STRING! Which you should not do, as it can strip important leading and trailing bits. It's a binary value, not ASCII. Trimming is BAD That will be really hard to return the CC numbers at all when you do that - and I think he needs to store the numbers for records. It'd be easier to just encrypt the numbers and decrypt them when needed I realize this, i was simply telling him a better way to hash. And it's not really hard - it's impossible without brute forcing. Why you'd do that to your own data, I'm not entirely sure. Quote Link to comment Share on other sites More sharing options...
PFMaBiSmAd Posted June 27, 2008 Share Posted June 27, 2008 @Jabop, I think you need to read the code you posted. In the encrypt function is this line - return trim($CryptStr); That will remove any leading or trailing trim-able characters from the encrypted function, destroying the encrypted cypher. Quote Link to comment Share on other sites More sharing options...
discomatt Posted June 27, 2008 Share Posted June 27, 2008 @ broken So the value is first stored in the DB in plain text, then encrypted and re-stored? This seems inefficient. Anyways, here's code that's worked for me on my test system. <?php define("ENCKEY", "SomeRandomKey"); function enc($str) { $size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($size, MCRYPT_RAND); return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, ENCKEY, $str, MCRYPT_MODE_ECB, $iv); } function dec ($str) { $size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($size, MCRYPT_RAND); return trim( mcrypt_decrypt(MCRYPT_RIJNDAEL_256, ENCKEY, $str, MCRYPT_MODE_ECB, $iv) ); } /* table data CREATE TABLE `test_crypt` ( `data` BLOB NOT NULL ) ENGINE = innodb; */ echo <<<HEREDOC <form method="post" action=""> <input type="text" name="str"><br /> <input type="submit" value="Submit"><br /> <br /> HEREDOC; mysql_connect('localhost', 'root', ''); mysql_select_db('test'); if ( $_POST['str'] ) if ( !mysql_query("INSERT INTO `test_crypt` SET `data` = '" . mysql_real_escape_string( enc($_POST['str']) ) . "'" ) ) echo 'Your query sucks!<br />' . mysql_error() . '<br />'; $r = mysql_query( 'SELECT `data` FROM `test_crypt`' ); if ( !$r ) echo 'Your second query sucks!<br />' . mysql_error() . '<br />'; else while ( $d = mysql_fetch_assoc($r) ) { echo '<br />Encrypted string: ' . $d['data']; echo '<br />Decrypted string: ' . dec( $d['data'] ); echo '<br />'; } ?> Returns something like this (linebreaks added for readability): <form method="post" action=""> <input type="text" name="str"><br /> <input type="submit" value="Submit"><br /> <br /><br /> Encrypted string: F „³¾å0õé9òæ|:K¸™AÿH/M=7/š <br /> Decrypted string: testing <br /><br /> Encrypted string: M1ŠP!®ÄÆ;ß"ˆÞúüyóð±î¸+zÃx‡ <br /> Decrypted string: zomgS! <br /> Quote Link to comment Share on other sites More sharing options...
br0ken Posted June 27, 2008 Author Share Posted June 27, 2008 @ broken So the value is first stored in the DB in plain text, then encrypted and re-stored? This seems inefficient. Anyways, here's code that's worked for me on my test system. No, the credit card numbers are in the database currently as samples. I'm extracting that number and entering the decrypted version into the database and then extracting it and attempting to decrypt it. Once I've got it working I'll integrate it into my actual system. Thanks for the sample code, I shall give it a try now! Quote Link to comment Share on other sites More sharing options...
br0ken Posted June 27, 2008 Author Share Posted June 27, 2008 This worked perfectly! Thank you so much everybody for helping me out. One more question I have... With the decrypted string being binary information, if it's saved in a ascii file backup, could it still be restored or would this corrupt the data? Quote Link to comment Share on other sites More sharing options...
discomatt Posted June 27, 2008 Share Posted June 27, 2008 The decrypted string is ASCII, the encrypted string is binary. Storing encrypted strings in a text file may be an issue, as there's no 'safe' way to separate the values... as you can see in my example, the encrypted string for 'testing' created a linebreak when displayed in ascii... A way to do it might be to store it 'line-by-line', starting the line with the length of the encrypted string in bits, then a known character, say a hyphen, then the encrypted string... That way, when you parse it, you can create a function that will read the first line, grab the numeric length, skip the known character, then read until the length is up, then look for a linebreak, and repeat. Quote Link to comment Share on other sites More sharing options...
PFMaBiSmAd Posted June 27, 2008 Share Posted June 27, 2008 Define: "saved in a ascii file backup" A standard .sql dump saves binary fields in hex. The following is from the test db I made for this thread - INSERT INTO `cc` (`id`,`cc`) VALUES (0,0x1D7B95F18CED5D336B75EB4864529C8C14C7279EDC68203D90F73026ED6C193DEBE66608CEC557E868D68E83265E528F1CA8B4B414620762069E9B1BB3AF6BD9); Quote Link to comment Share on other sites More sharing options...
discomatt Posted June 27, 2008 Share Posted June 27, 2008 Mmm.. and you can use the bin2hex() function to convert your binary strings to hex Quote Link to comment Share on other sites More sharing options...
br0ken Posted June 27, 2008 Author Share Posted June 27, 2008 Unfortunately our server wont allow us to run a sql dump so I've written my own script to perform the same task. I've got the encrypted credit card number to store in a TEXT field and it works ok. Because it's in a text field, would it be ok in an ascii file? Also, bin2hex is good but is there a function to reverse this? I know hex2bin doesn't exist but is there an equivilant? Quote Link to comment Share on other sites More sharing options...
discomatt Posted June 27, 2008 Share Posted June 27, 2008 Check the bin2hex user comments. http://php.net/manual/en/function.bin2hex.php Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.