I've written a password encryption algorithm in PHP, which (I think) is not very vulnerable to rainbowtable attacks. It's just that I don't have a lot of experience with encryptions, nor PHP. But from the knowledge I have I think this is a hashing algorithm which automatically adds salt, but I actually have no idea if this is true or not, so please tell me.
This is the code I use to create a password hash:
<?php $pass = $argv[1]; $pass_len = strlen($pass) - 1; $pass_chars = str_split($pass, 1); // Convert password characters to their ASCII values foreach ($pass_chars as $key => $val) { $pass_chars[$key] = ord($val); } // Generate an array of random characters the size of $pass_chars for ($i = 0; $i < $pass_len + 1; $i++) { $rand_chars[$i] = mt_rand(33, 126); } // Create list of added $pass_vals values foreach ($pass_chars as $key => $val) { $pass_vals[$key] = $val + $pass_chars[$key + 1]; } $pass_vals[$pass_len] = $pass_chars[$pass_len] + $pass_chars[0]; // Create list of added $rand_vals values foreach ($rand_chars as $key => $val) { $rand_vals[$key] = $val + $rand_chars[$key + 1]; } $rand_vals[$pass_len] = $rand_chars[$pass_len] + $rand_chars[0]; // Add $rand_vals to $pass_chars foreach ($pass_chars as $key => $val) { $pass_chars[$key] += $rand_vals[$key]; } // Add $pass_vals to $rand_chars foreach ($rand_chars as $key => $val) { $rand_chars[$key] += $pass_vals[$key]; } // Create combined array $i = 1; foreach ($pass_chars as $key => $val) { $combined[$key * 2] = str_pad($pass_chars[$key], 3, "0", STR_PAD_LEFT); $combined[$i] = str_pad($rand_chars[$key], 3, "0", STR_PAD_LEFT); $i += 2; } // Print $combined as string echo implode($combined) . "\n";?>And this code to reverse it:
<?php $pass_i = $argv[1]; $hash = $argv[2]; $pass_len_i = strlen($pass_i) - 1; $pass_chars_i = str_split($pass_i, 1); $hash_chars = str_split($hash, 3); $hash_len = sizeof($hash_chars); // Convert input password characters to their ASCII values foreach ($pass_chars_i as $key => $val) { $pass_chars_i[$key] = ord($val); } // Create list of added $pass_vals_i values foreach ($pass_chars_i as $key => $val) { $pass_vals_i[$key] = $val + $pass_chars_i[$key + 1]; } $pass_vals_i[$pass_len_i] = $pass_chars_i[$pass_len_i] + $pass_chars_i[0]; // Remove extra '0's at the left in $hash_chars if there are any foreach ($hash_chars as $key => $val) { $hash_chars[$key] = ltrim($val, "0"); } // Extract $rand_chars and $pass_chars from $hash_chars $i = 1; foreach ($hash_chars as $key => $val) { $pass_chars[$key] = $hash_chars[$key * 2]; $rand_chars[$key] = $hash_chars[$i]; $i += 2; } // Subtract $pass_vals_i from $rand_chars foreach ($rand_chars as $key => $val) { $rand_chars[$key] -= $pass_vals_i[$key]; } // Create list of $rand_vals by adding $rand_chars values foreach ($rand_chars as $key => $val) { $rand_vals[$key] = $val + $rand_chars[$key + 1]; } $rand_vals[$pass_len_i] = $rand_chars[$pass_len_i] + $rand_chars[0]; // Subtract $rand_vals from $pass_chars foreach ($pass_chars as $key => $val) { $pass_chars[$key] -= $rand_vals[$key]; } foreach ($pass_chars as $key => $val) { $pass_chars[$key] = chr($val); } // Print $pass_chars as string echo implode($pass_chars) . "\n";?>I would like to know if this is secure, and why I can't get it to compare$pass_i with$pass in the reversing script.
I've hashed the word "password" 100 times, and this is the list of hashes:
279288252300292297275344234280242290239280238271307317310299276356224269311304346343344331321325262326212245250312203287197265207268259267309304253272235290233290279292262336218262276284255304207267169249210265239294255294297297298328228282276268235317214263300300314349292301304319244297288294257303251299289301346337268345218251252279187242251254301342265308310306336340290324199278322298319333269331246287241308258269328317300323201253253257284341285292274342235268236295185253227283196253249288238310262277311321335318291329216244260281295324252320225281239280292287240317258285249282269312231306215274204277268255289325267303270273320342275327231297278270345336303321262281226290283281330351316328249324203253222262245290253264317334326332300343234293238269250281259267258301281302291328234312269258341339260314254294189269224265272308235313269258344339290317231243278297271326209294211264251283277296215293330322289317266317292298275343209268237269281280203256267256289356256282297323237310222255214279239250217298195264279280283348273271327330238309265265280309314316286347282288253330193251198254272303236278255303228301269276328329275327242260326321290314322321330350326329340333296335273273322296308335306318329337304341269299315298304329219265226263294308303335264317229283293274275331291311264289291320297320283326293293297328271281253300261262337344343342365350335351336312315336260250271319296297288348233289285280325333233304274309281274315352273312319310348345341331310322274245310338323317360355345354254327261255242318251264252296239301224287227286228277266279242299295312287292345340322354305317254324235258280289268311249266250328254271332332334336278326254264268264240313214272274291262332250266261312204261244249280304267321298295367352360351293337196268200249243260305328256326277279309334298303235307201257198253297290326356322319330339336319265329277305214281216278279287322341329317319340275291277298298288333355248327280270265346234247276299290290297309327333320343289326227299274256299330308332248285245308288286296351253281250300273262227267230269280306311323291337241290277279256310258277248290313303294359287284303339249292225269276292230293227282291294274346268264301332252281197259198247251296292304298337226297247257240302241303236247289334291304329336249329221248267285240283234266277313309313315345307306273329218256284298220295262270342341274350217260219285223246226288210247268308265309270305234301217261235268249275273283262335196276212269199279240248258304288289232308266269281346210284206262263272271303269304266274340337323352297320312313283327251268248299211258257298222308230263290303318315293315261295231275228301218276303291334348324314296322305316300298288347288290283347251272263307263268254298274265302354234297235286286285277329237260331330229310210264231295230285287281328334315306310313273306249312291286289354279271290336258266234284255259290341291298323342268317248279244281279313284275297354225292284282287338280277307315248298234259267320297296326350321312312337264287293275321327309339304319276334242278297292271317185249231245300331272318303303309336291301230302207252260264264341258272304335252305229275197266281307224283221286275284314340304310329322305319309312236306200275270274291345278282263324242251277309211277228279246298256297244295283277306318289319223279259289254319254284254306227276261263269273251305302291293360233282295287287336215263255267297297273345241277306313295329315294279333249272267286295326267318304298349342268335196245245275250279294316333327303355264284271308229275307280308336277317270309294310259320250267254295260303241266299320257328244278266302270292272290319330289298266336225279307295288348289268342333343320340332307353255303297301252332231248294295240287200262223283267289298327309307310330258292246264217291192271237270311316333331294330219276269301198277224266242307252284253304235277250270298325221282272284298337325310301351240278278274262289255282272318231303238277292297322323279311253248301314339332358356302351236287257277219292306295240320227265316311363354295345279278287313332308329333285341295293353351270338252260291304245279279275342349281342243288297291304334240282242282217269220293206276273279285330268283258297231279204261280288330341345338347343282332220262276296208289210264274295255328250263273315245270316297324328327341257335245271297310305315278302312310242311206276208279263278316321282323260271351322307338276314311311341349304328258304267266330312305327247323206273290282335344268319252261285321214273231286272294250327235259289304297297301302245308273282254340215263274288270314249268298313221294204272242281252310216278250266288296280251293338289300271338297282302351250279213283224242266291310320270339225280265281292312213292241285222265310302275357210267289279360338298334All of them are unique, and all of them are reversible.This is why I think this algorithm is not very vulnerable to rainbowtables.
Let me know how to improve the code, and potential ways to exploit it.
- 3\$\begingroup\$If this is to store passwords, don't do that. Instead, read this:security.stackexchange.com/questions/211/… (Basically: don't roll your own!)\$\endgroup\$Ismael Miguel– Ismael Miguel2015-08-19 14:34:49 +00:00CommentedAug 19, 2015 at 14:34
- \$\begingroup\$@IsmaelMiguel Why exactly shouldn't I use this? Even if it would be a good algorithm, should I still use a commonly used one, or is this algorithm flawed and that's why I shouldn't use it?\$\endgroup\$insanikov– insanikov2015-08-19 14:41:49 +00:00CommentedAug 19, 2015 at 14:41
- 1\$\begingroup\$You shouldn't use this because it isn't tested and re-tested overany attack vector. All common algorithms are tested over the years, released into the public. One of the things that occurs me is that your code is vulnerable against malicious changes in the encrypted data, cold boot attacks and timming attacks. Remember this: if it is reversible, it is breakable. If it isn't reversible, you have an hash and you only need to find a colision.\$\endgroup\$Ismael Miguel– Ismael Miguel2015-08-19 15:37:20 +00:00CommentedAug 19, 2015 at 15:37
- \$\begingroup\$@IsmaelMiguel Okay, I understand, thank you for the feedback.\$\endgroup\$insanikov– insanikov2015-08-19 15:41:36 +00:00CommentedAug 19, 2015 at 15:41
- \$\begingroup\$One thing I've noticed is that your results all start with 1, 2 or 3 being 2 the most commum one. The first 3 digits in most results have some relationship with the last 3.\$\endgroup\$Ismael Miguel– Ismael Miguel2015-08-19 15:41:43 +00:00CommentedAug 19, 2015 at 15:41
1 Answer1
Security
I'm assuming this is for educational purposes. Otherwise, don't roll your own, use bcrypt.
From a quick look at it, it seems that the core of your algorithm basically boils down to this:
foreach character in password: character += random(33, 126);There are more additions, but they do not seem to affect the basic principle.
This means that an attacker can gain at least some information about the password by looking at the encrypted password. An encrypteda will statistically have a smaller value than an encryptedz.
You can see this easily by adjusting the range from which random numbers are selected. Using for examplemt_rand(33, 35);, encryptingaz will result in this:166253191254,165253190253,167254192254, etc. You can see that166 is smaller than191,165 is smaller than190, or167 is smaller than192.
Making the random range larger makes this problem less sever, but it still exists.z for example can reach values which other characters can never reach. So whenever you see374, you know for sure that it's az. When you see167 you can be pretty sure that it's ana, and so on. This makes brute-force attempts significantly easier for an attacker.
Additionally, the size of the password is easily calculated given the encrypted password. This should not happen.
Also, note the documentation ofmt_rand:Caution: This function does not generate cryptographically secure values, and should not be used for cryptographic purposes.
I haven't looked at the decryption code in-depth, so I'm not sure if there are more weaknesses, but there very well might be (I'm not yet 100% convinced that the original password is even needed for decryption).
Code
- Your variable naming is very confusing. What's the difference between a
valand achar? They seem to stand for the same thing? In that case, use the same name. If they stand for different concepts, use clearer names, or add comments. - Comments: Your comments basically describe what your code does. But I already know that from looking at the code. As this is relatively complicated code, I would actually like to have comments that describe why the code does what it does; what's the use of each of the for loops? What's the general idea of the algorithm? etc.
- order of code blocks: your different foreach blocks seem to be randomly ordered. First, you work on the
pass_chars, then onrand_chars, then onpass_chars/pass_valsagain, then again onrand_chars/rand_vals. As these do not depend on each other yet, it would make more sense to first work onpass_*, then onrand_*. - With an input of
pass, I get a warning:Notice: Undefined offset: 4 in /var/www/e.php on line 19
- \$\begingroup\$This is for educational purposes indeed, I have realized this is not solid and I won't use this in real situations. About the code blocks order; these need to be executed in a specific order, first I convert the characters to their ascii values, add a random character inbetween each one, a sum of the ascii value of the random characters will be added to the original character inbetween, then I add the sum of the original input to the random character inbetween, so this has to be done in the correct order. And I don't understand what causes the error, is it when you are encrypting or reversing?\$\endgroup\$insanikov– insanikov2015-08-20 17:54:14 +00:00CommentedAug 20, 2015 at 17:54
- \$\begingroup\$@insanikov I mean the first 4 loops of the encryption, those do not yet depend on each other, so I would order them differently. And the notice is when I'm encrypting\$\endgroup\$tim– tim2015-08-20 17:56:50 +00:00CommentedAug 20, 2015 at 17:56
- \$\begingroup\$You are completely correct, I will rearrange those loops. About the notice; I never get that notice when I use terminal to run, I will try to run it in my browser later (at least I think that's what you do).\$\endgroup\$insanikov– insanikov2015-08-20 18:11:53 +00:00CommentedAug 20, 2015 at 18:11
- \$\begingroup\$@insanikov Yes, right, I used a browser, and I have php set to show all notices.\$\endgroup\$tim– tim2015-08-20 18:13:57 +00:00CommentedAug 20, 2015 at 18:13
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.
