3
\$\begingroup\$

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:

279288252300292297275344234280242290239280238271307317310299276356224269311304346343344331321325262326212245250312203287197265207268259267309304253272235290233290279292262336218262276284255304207267169249210265239294255294297297298328228282276268235317214263300300314349292301304319244297288294257303251299289301346337268345218251252279187242251254301342265308310306336340290324199278322298319333269331246287241308258269328317300323201253253257284341285292274342235268236295185253227283196253249288238310262277311321335318291329216244260281295324252320225281239280292287240317258285249282269312231306215274204277268255289325267303270273320342275327231297278270345336303321262281226290283281330351316328249324203253222262245290253264317334326332300343234293238269250281259267258301281302291328234312269258341339260314254294189269224265272308235313269258344339290317231243278297271326209294211264251283277296215293330322289317266317292298275343209268237269281280203256267256289356256282297323237310222255214279239250217298195264279280283348273271327330238309265265280309314316286347282288253330193251198254272303236278255303228301269276328329275327242260326321290314322321330350326329340333296335273273322296308335306318329337304341269299315298304329219265226263294308303335264317229283293274275331291311264289291320297320283326293293297328271281253300261262337344343342365350335351336312315336260250271319296297288348233289285280325333233304274309281274315352273312319310348345341331310322274245310338323317360355345354254327261255242318251264252296239301224287227286228277266279242299295312287292345340322354305317254324235258280289268311249266250328254271332332334336278326254264268264240313214272274291262332250266261312204261244249280304267321298295367352360351293337196268200249243260305328256326277279309334298303235307201257198253297290326356322319330339336319265329277305214281216278279287322341329317319340275291277298298288333355248327280270265346234247276299290290297309327333320343289326227299274256299330308332248285245308288286296351253281250300273262227267230269280306311323291337241290277279256310258277248290313303294359287284303339249292225269276292230293227282291294274346268264301332252281197259198247251296292304298337226297247257240302241303236247289334291304329336249329221248267285240283234266277313309313315345307306273329218256284298220295262270342341274350217260219285223246226288210247268308265309270305234301217261235268249275273283262335196276212269199279240248258304288289232308266269281346210284206262263272271303269304266274340337323352297320312313283327251268248299211258257298222308230263290303318315293315261295231275228301218276303291334348324314296322305316300298288347288290283347251272263307263268254298274265302354234297235286286285277329237260331330229310210264231295230285287281328334315306310313273306249312291286289354279271290336258266234284255259290341291298323342268317248279244281279313284275297354225292284282287338280277307315248298234259267320297296326350321312312337264287293275321327309339304319276334242278297292271317185249231245300331272318303303309336291301230302207252260264264341258272304335252305229275197266281307224283221286275284314340304310329322305319309312236306200275270274291345278282263324242251277309211277228279246298256297244295283277306318289319223279259289254319254284254306227276261263269273251305302291293360233282295287287336215263255267297297273345241277306313295329315294279333249272267286295326267318304298349342268335196245245275250279294316333327303355264284271308229275307280308336277317270309294310259320250267254295260303241266299320257328244278266302270292272290319330289298266336225279307295288348289268342333343320340332307353255303297301252332231248294295240287200262223283267289298327309307310330258292246264217291192271237270311316333331294330219276269301198277224266242307252284253304235277250270298325221282272284298337325310301351240278278274262289255282272318231303238277292297322323279311253248301314339332358356302351236287257277219292306295240320227265316311363354295345279278287313332308329333285341295293353351270338252260291304245279279275342349281342243288297291304334240282242282217269220293206276273279285330268283258297231279204261280288330341345338347343282332220262276296208289210264274295255328250263273315245270316297324328327341257335245271297310305315278302312310242311206276208279263278316321282323260271351322307338276314311311341349304328258304267266330312305327247323206273290282335344268319252261285321214273231286272294250327235259289304297297301302245308273282254340215263274288270314249268298313221294204272242281252310216278250266288296280251293338289300271338297282302351250279213283224242266291310320270339225280265281292312213292241285222265310302275357210267289279360338298334

All 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.

200_success's user avatar
200_success
146k22 gold badges191 silver badges481 bronze badges
askedAug 19, 2015 at 14:29
insanikov's user avatar
\$\endgroup\$
13
  • 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\$CommentedAug 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\$CommentedAug 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\$CommentedAug 19, 2015 at 15:37
  • \$\begingroup\$@IsmaelMiguel Okay, I understand, thank you for the feedback.\$\endgroup\$CommentedAug 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\$CommentedAug 19, 2015 at 15:41

1 Answer1

3
\$\begingroup\$

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 aval and 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 thepass_chars, then onrand_chars, then onpass_chars/pass_vals again, 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 ofpass, I get a warning:Notice: Undefined offset: 4 in /var/www/e.php on line 19
answeredAug 20, 2015 at 17:32
tim's user avatar
\$\endgroup\$
4
  • \$\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\$CommentedAug 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\$CommentedAug 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\$CommentedAug 20, 2015 at 18:11
  • \$\begingroup\$@insanikov Yes, right, I used a browser, and I have php set to show all notices.\$\endgroup\$CommentedAug 20, 2015 at 18:13

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.