Autor Beitrag
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 01.01.09 16:12 
Ich beschäftige mich derzeit damit, verschiedene Hash-Funktionen für PHP zu portieren, da bei PHP nicht alle Algorithmen für Crypt implementiert sind (Speziell die Algorithmen, die mit SHA256 und SHA512 arbeiten).

Ich hab auch eine entsprechende Anleitung mit zugehörigem C-Source gefunden, jedoch erhalte ich, wenn ich nach dieser Anleitung vorgehe, falsche Ausgaben für die angegebenen Testvektoren.

Meine derzeitige Implementation sieht so aus:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379:
380:
381:
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
<?

include "salt_api.php";
include "random_gendata.php";

if(!function_exists('sha512')) {
  function sha512($data,$raw=false){
//    if(false === array_search('sha512', hash_algos(), true)) {
//      return false;
//    }

    return hash('sha512', $data, $raw);
  }
}

function crypt_sha512($password, $salt = "")
{
  $i_rounds = 5000;
  $i_salt = '';
  $i_has_rounds = false;

  if(!empty($salt)) {
    if(substr($salt, 03) != '$6$') {
      return false;
    }

    //We know it's a SHA256 hash salt
    $salt = substr($salt, 3);

    //Check for rounds specification
    if(strtolower(substr($salt, 07)) == 'rounds=') {
      $i = strpos($salt, '$');
      if(false !== $i) {
        $s = substr($salt, 7, $i-7);
        $i_rounds = @(int)$s;
        $i_has_rounds = true;
        $salt = substr($salt, $i+1);
      }
    }

    $i = strpos($salt, '$');
    if(false !== $i) {
      $salt = substr($salt, 0, $i);
    }

    $i_salt = $salt;
  } else {
    $i_salt = gen_salt(16);
  }

  if($i_rounds < 1000) {
    $i_rounds = 1000;
  } else if($i_rounds > 999999999) {
    $i_rounds = 999999999;
  }

  $i_salt = substr($i_salt, 016);

  //Undefine temp variables
  unset($i);
  unset($rounds);
  unset($salt);

  //Initialization done ... now calculate the hash ...
/**
  Implementation based on http://people.redhat.com/drepper/SHA-crypt.txt

   1.  start digest A

   2.  the password string is added to digest A

   3.  the salt string is added to digest A.  This is just the salt string
   itself without the enclosing '$', without the magic prefix $5$ and
   $6$ respectively and without the rounds=<N> specification.

   NB: the MD5 algorithm did add the $1$ prefix.  This is not deemed
   necessary since it is a constant string and does not add security
   and /possibly/ allows a plain text attack.  Since the rounds=<N>
   specification should never be added this would also create an
   inconsistency.

   4.  start digest B

   5.  add the password to digest B

   6.  add the salt string to digest B

   7.  add the password again to digest B

   8.  finish digest B

   9.  For each block of 32 or 64 bytes in the password string (excluding
   the terminating NUL in the C representation), add digest B to digest A

   10. For the remaining N bytes of the password string add the first
   N bytes of digest B to digest A

   11. For each bit of the binary representation of the length of the
   password string up to and including the highest 1-digit, starting
   from to lowest bit position (numeric value 1):

   a) for a 1-digit add digest B to digest A

   b) for a 0-digit add the password string

   NB: this step differs significantly from the MD5 algorithm.  It
   adds more randomness.

   12. finish digest A

   13. start digest DP

   14. for every byte in the password (excluding the terminating NUL byte
   in the C representation of the string)

   add the password to digest DP

   15. finish digest DP

   16. produce byte sequence P of the same length as the password where

   a) for each block of 32 or 64 bytes of length of the password string
   the entire digest DP is used

   b) for the remaining N (up to  31 or 63) bytes use the first N
   bytes of digest DP

   17. start digest DS

   18. repeast the following 16+A[0] times, where A[0] represents the first
   byte in digest A interpreted as an 8-bit unsigned value

   add the salt to digest DS

   19. finish digest DS

   20. produce byte sequence S of the same length as the salt string where

   a) for each block of 32 or 64 bytes of length of the salt string
   the entire digest DS is used

   b) for the remaining N (up to  31 or 63) bytes use the first N
   bytes of digest DS

   21. repeat a loop according to the number specified in the rounds=<N>
   specification in the salt (or the default value if none is
   present).  Each round is numbered, starting with 0 and up to N-1.

   The loop uses a digest as input.  In the first round it is the
   digest produced in step 12.  In the latter steps it is the digest
   produced in step 13.h.  The following text uses the notation
   "digest A/C" to desribe this behavior.


   a) start digest C

   b) for odd round numbers add the byte sequense P to digest C

   c) for even round numbers add digest A/C

   d) for all round numbers not divisible by 3 add the byte sequence S

   e) for all round numbers not divisible by 7 add the byte sequence P

   f) for odd round numbers add digest A/C

   g) for even round numbers add the byte sequence P

   h) finish digest C.

   22. Produce the output string.  This is an ASCII string of the maximum
   size specified above, consisting of multiple pieces:

   a) the salt prefix, $5$ or $6$ respectively

   b) the rounds=<N> specification, if one was present in the input
   salt string.  A trailing '$' is added in this case to separate
   the rounds specification from the following text.

   c) the salt string truncated to 16 characters

   d) a '$' character

   e) the base-64 encoded final C digest.  The encoding used is as
   follows:

                111111111122222222223333333333444444444455555555556666
   0123456789012345678901234567890123456789012345678901234567890123
   ----------------------------------------------------------------
   ./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

   Each group of three bytes from the digest produces four
   characters as output:

   1. character: the six low bits of the first byte
   2. character: the two high bits of the first byte and the
   four low bytes from the second byte
   3. character: the four high butes from the second byte and
   the two low bits from the third byte
   4. character: the six high bits from the third byte

   The groups of three bytes are as follows (in this sequence).
   These are the indices into the byte array containing the
   digest, starting with index 0.  For the last group there are
   not enough bytes left in the digest and the value zero is used
   in its place.  This group also produces only three or two
   characters as output for SHA-256 and SHA-512 respecitevely.

   For SHA-256:

   #3   #2   #1   <-- byte number in group

   0 - 10 - 20
   21 -  1 - 11
   12 - 22 -  2
   3 - 13 - 23
   24 -  4 - 14
   15 - 25 -  5
   6 - 16 - 26
   27 -  7 - 17
   18 - 28 -  8
   9 - 19 - 29
   * - 31 - 30


   For SHA-512:

   #3   #2   #1   <-- byte number in group

   0 - 21 - 42
   22 - 43 -  1
   44 -  2 - 23
   3 - 24 - 45
   25 - 46 -  4
   47 -  5 - 26
   6 - 27 - 48
   28 - 49 -  7
   50 -  8 - 29
   9 - 30 - 51
   31 - 52 - 10
   53 - 11 - 32
   12 - 33 - 54
   34 - 55 - 13
   56 - 14 - 35
   15 - 36 - 57
   37 - 58 - 16
   59 - 17 - 38
   18 - 39 - 60
   40 - 61 - 19
   62 - 20 - 41
   * -  * - 63
*/


  //1+2+3
  //$d_A = $password . $i_salt;
  $d_A = hash_init('sha512');
  hash_update($d_A, $password);
  hash_update($d_A, $i_salt);

  //4+5+6+7+8
  //$d_B = sha512($password . $i_salt . $password, true);
  $d_B = hash_init('sha512');
  hash_update($d_B, $password);
  hash_update($d_B, $i_salt);
  hash_update($d_B, $password);
  $B = hash_final($d_B, true);

  //9+10
  //$d_A .= str_repeat($d_B, (int)(strlen($password) / 64));
  //$d_A .= substr($d_B, 0, strlen($password) % 64);
  for($i = strlen($password); $i >= strlen($B); $i -= strlen($B)) {
     hash_update($d_A, $B);
    }
  hash_update($d_A, substr($B, 0, $i));

  //11
  $i = strlen($password);
  while($i) {
    if($i&1) {
      //$d_A .= $d_B;
          hash_update($d_A, $B);
    } else {
      //$d_A .= $password;
          hash_update($d_A, $password);
    }
    $i >>= 1;
  }

  //12
  //$d_A = sha512($d_A, true);
  $A = hash_final($d_A, true);

  //13+14+15
  //$d_DP = sha512(str_repeat($password, strlen($password)), true);
  $d_DP = hash_init('sha512');
  for($i = strlen($password); $i; $i--) {
        hash_update($d_DP, $password);
    }
    $DP = hash_final($d_DP, true);

  //16
  //$P = str_repeat($d_DP, (int)(strlen($password) / 64));
  //$P .= substr($d_DP, 0, strlen($password) % 64);
  $P = '';
  for($i = strlen($password); $i >= strlen($DP); $i -= strlen($DP)) {
     $P .= $DP;
    }
  $P .= substr($DP, 0, $i);

  //17+18+19
  //$d_DS = sha512(str_repeat($i_salt, 16+ord($d_A[0])), true);
  $d_DS = hash_init('sha512');
  for($i = 16+ord($A[0]); $i; $i--) {
        hash_update($d_DS, $i_salt);
    }
    $DS = hash_final($d_DS, true);

  //20
  //$S = str_repeat($d_DS, (int)(strlen($i_salt) / 64));
  //$S .= substr($d_DS, 0, strlen($i_salt) % 64);
  $S = '';
  for($i = strlen($i_salt); $i >= strlen($DS); $i -= strlen($DS)) {
     $S .= $DS;
    }
  $S .= substr($DS, 0, $i);

  //21
  for($round = 0; $round < $i_rounds; $round++) {
        //21a
        $d_C = hash_init('sha512');

    //21a+b+c
    //if($round&1) {
    //  $d_C = $P;
    //} else {
    //  $d_C = $d_A;
    //}
    if($round&1) {
      hash_update($d_C, $P);
    } else {
      hash_update($d_C, $A);
    }

    //21d
    if($round%3) {
      //$d_C .= $S;
      hash_update($d_C, $S);
    }
    //21e
    if($round%7) {
      //$d_C .= $P;
      hash_update($d_C, $P);
    }
    //if($round&1) {
    //  //21f
    //  $d_C .= $d_A;
    //} else {
    //  //21g
    //  $d_C .= $P;
    //}
    //21f+g
    if($round&1) {
      hash_update($d_C, $A);
    } else {
      hash_update($d_C, $P);
    }
    //21h
    //$d_A = sha512($d_C, true);
    $A = hash_final($d_C, true);
  }

  //22a
  $result = '$6$';

  //22b
  if($i_has_rounds || ($i_rounds != 5000)) {
    $result .= "rounds={$i_rounds}\$";
  }

  //22c+d
  $result .= $i_salt . '$';

  //22e
  //Reorder digest bytes
  $pos = array(
    4221014322232444524344625,
    2654748276749282985051309,
    105231321153543312135534351456,
    573615165837381759603918196140,
    41206263);

  $tmp = '';
  for($i = 0; $i < 64; $i++) {
    $tmp .= $A[$pos[$i]];
  }

  $tmp = strtr(base64_encode($tmp),
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    $tmp = str_replace('=''', $tmp);

  $result .= $tmp;
  return $result;
}

$tv = array(
  array( '$6$saltstring''Hello world!',
    '$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1' ),
  array( '$6$rounds=10000$saltstringsaltstring''Hello world!',
    '$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v.' ),
  array( '$6$rounds=5000$toolongsaltstring''This is just a test',
    '$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQzQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0' ),
  array( '$6$rounds=1400$anotherlongsaltstring',
    'a very much longer text to encrypt.  This one even stretches over morethan one line.',
    '$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wPvMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1' ),
  array( '$6$rounds=77777$short',
    'we have a short salt string but not a short password',
    '$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0gge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0' ),
  array( '$6$rounds=123456$asaltof16chars..''a short string',
    '$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1' ),
  array( '$6$rounds=10$roundstoolow''the minimum number is still observed',
    '$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1xhLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX.' )
);

foreach($tv as $tvd) {
    echo crypt_sha512($tvd[1], $tvd[0]) . "\n" . $tvd[2] . "\n<br/>\n";
}

?>


Die in der Datei eingebundenen Includes werden für den Selftest nicht benötigt; diese sind nur für die Generierung zufälliger Hashes zuständig, sofern kein solcher angegeben wurde.

Würde mich über zielführende Hinweise sehr freuen.

TIA,
BenBE.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
BenBE Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 01.01.09 18:16 
Ok, hab den Fehler in meiner Implementation gefunden: Ich hatte beim Encodieren der Result-Hashes einen Fehler drin. Base64_encode mit Übersetzugnstabelle funktionierte nicht wie erwartet; macht man's per Hand, geht's ...

Naja, hier die korrigierten Sources, falls jemand wirklich sichere Passwort-Hashes nutzen will:

ausblenden volle Höhe crypt_sha256.php
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
<?

include "salt_api.php";

if(!function_exists('sha256')) {
  function sha256($data,$raw=false){
    if(false === array_search('sha256', hash_algos(), true)) {
      return false;
    }

    return hash('sha256', $data, $raw);
  }
}

function crypt_sha256($password, $salt = "")
{
  $i_rounds = 5000;
  $i_salt = '';
  $i_has_rounds = false;

  if(!empty($salt)) {
    if(substr($salt, 0,3) != '$5$') {
      return false;
    }

    //We know it's a SHA256 hash salt
    $salt = substr($salt, 3);

    //Check for rounds specification
    if(strtolower(substr($salt, 07)) == 'rounds=') {
      $i = strpos($salt, '$');
      if(false !== $i) {
        $s = substr($salt, 7, $i-7);
        $i_rounds = @(int)$s;
        $i_has_rounds = true;
        $salt = substr($salt, $i+1);
      }
    }

    $i = strpos($salt, '$');
    if(false !== $i) {
      $salt = substr($salt, 0, $i);
    }

    $i_salt = $salt;
  } else {
    $i_salt = gen_salt(16);
  }

  if($i_rounds < 1000) {
    $i_rounds = 1000;
  } else if($i_rounds > 999999999) {
    $i_rounds = 999999999;
  }

  $i_salt = substr($i_salt, 016);

  //Undefine temp variables
  unset($i);
  unset($rounds);
  unset($salt);

  //Initialization done ... now calculate the hash ...
/**
  Implementation based on http://people.redhat.com/drepper/SHA-crypt.txt
*/


  //1+2+3
  $d_A = hash_init('sha256');
  hash_update($d_A, $password);
  hash_update($d_A, $i_salt);

  //4+5+6+7+8
  $d_B = hash_init('sha256');
  hash_update($d_B, $password);
  hash_update($d_B, $i_salt);
  hash_update($d_B, $password);
  $B = hash_final($d_B, true);

  //9+10
  for($i = strlen($password); $i >= strlen($B); $i -= strlen($B)) {
     hash_update($d_A, $B);
    }
  hash_update($d_A, substr($B, 0, $i));

  //11
  $i = strlen($password);
  while($i) {
    if($i&1) {
          hash_update($d_A, $B);
    } else {
          hash_update($d_A, $password);
    }
    $i >>= 1;
  }

  //12
  $A = hash_final($d_A, true);

  //13+14+15
  $d_DP = hash_init('sha256');
  for($i = strlen($password); $i; $i--) {
        hash_update($d_DP, $password);
    }
    $DP = hash_final($d_DP, true);

  //16
  $P = '';
  for($i = strlen($password); $i >= strlen($DP); $i -= strlen($DP)) {
     $P .= $DP;
    }
  $P .= substr($DP, 0, $i);

  //17+18+19
  $d_DS = hash_init('sha256');
  for($i = 16+ord($A[0]); $i; $i--) {
        hash_update($d_DS, $i_salt);
    }
    $DS = hash_final($d_DS, true);

  //20
  $S = '';
  for($i = strlen($i_salt); $i >= strlen($DS); $i -= strlen($DS)) {
     $S .= $DS;
    }
  $S .= substr($DS, 0, $i);

  //21
  for($round = 0; $round < $i_rounds; $round++) {
        //21a
        $d_C = hash_init('sha256');

    //21a+b+c
    if($round&1) {
      hash_update($d_C, $P);
    } else {
      hash_update($d_C, $A);
    }

    //21d
    if($round%3) {
      hash_update($d_C, $S);
    }
    //21e
    if($round%7) {
      hash_update($d_C, $P);
    }
    //21f+g
    if($round&1) {
      hash_update($d_C, $A);
    } else {
      hash_update($d_C, $P);
    }
    //21h
    $A = hash_final($d_C, true);
  }

  //22a
  $result = '$5$';

  //22b
  if($i_has_rounds || ($i_rounds != 5000)) {
    $result .= "rounds={$i_rounds}\$";
  }

  //22c+d
  $result .= $i_salt . '$';

  //22e
  //Encode digest bytes
  $tmp = crypt_sha256_encode($A);

  $result .= $tmp;
  return $result;
}

function crypt_sha256_encode($data){
    $chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  $pos = array(
       0 , 10 , 20,  21 ,  1 , 11,  12 , 22 ,  2,   3 , 13 , 23,
      24 ,  4 , 14,  15 , 25 ,  5,   6 , 16 , 26,  27 ,  7 , 17,
      18 , 28 ,  8,   9 , 19 , 29,  -1 , 31 , 30
        );

    $result = '';

    for($i = 0; $i < count($pos);) {
        $B2 = $pos[$i++];
        $B1 = $pos[$i++];
        $B0 = $pos[$i++];
        $B2 = $B2 < 0 ? 0 : ord($data[$B2]);
        $B1 = $B1 < 0 ? 0 : ord($data[$B1]);
        $B0 = $B0 < 0 ? 0 : ord($data[$B0]);

        $n = 4;
        if($pos[$i-3] < 0) {
            $n--;
        }
        if($pos[$i-2] < 0) {
            $n--;
        }

        $w = ($B2 << 16) + ($B1 << 8) + $B0;
        while($n--) {
            $result .= $chars[$w & 0x3F];
            $w >>= 6;
        }
    }

    return $result;
}

$tv = array(
  array( '$5$saltstring''Hello world!',
    '$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5' ),
  array( '$5$rounds=10000$saltstringsaltstring''Hello world!',
    '$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA' ),
  array( '$5$rounds=5000$toolongsaltstring''This is just a test',
    '$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8mGRcvxa5' ),
  array( '$5$rounds=1400$anotherlongsaltstring',
    'a very much longer text to encrypt.  This one even stretches over morethan one line.',
    '$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12oP84Bnq1' ),
  array( '$5$rounds=77777$short',
    'we have a short salt string but not a short password',
    '$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/' ),
  array( '$5$rounds=123456$asaltof16chars..''a short string',
    '$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/cZKmF/wJvD' ),
  array( '$5$rounds=10$roundstoolow''the minimum number is still observed',
    '$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL972bIC' ),
);

foreach($tv as $tvd) {
    echo crypt_sha256($tvd[1], $tvd[0]) . "\n" . $tvd[2] . "\n<br/>\n";
}

?>


ausblenden volle Höhe crypt_sha512.php
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
<?

include "salt_api.php";

if(!function_exists('sha512')) {
  function sha512($data,$raw=false){
    if(false === array_search('sha512', hash_algos(), true)) {
      return false;
    }

    return hash('sha512', $data, $raw);
  }
}

function crypt_sha512($password, $salt = "")
{
  $i_rounds = 5000;
  $i_salt = '';
  $i_has_rounds = false;

  if(!empty($salt)) {
    if(substr($salt, 03) != '$6$') {
      return false;
    }

    //We know it's a SHA256 hash salt
    $salt = substr($salt, 3);

    //Check for rounds specification
    if(strtolower(substr($salt, 07)) == 'rounds=') {
      $i = strpos($salt, '$');
      if(false !== $i) {
        $s = substr($salt, 7, $i-7);
        $i_rounds = @(int)$s;
        $i_has_rounds = true;
        $salt = substr($salt, $i+1);
      }
    }

    $i = strpos($salt, '$');
    if(false !== $i) {
      $salt = substr($salt, 0, $i);
    }

    $i_salt = $salt;
  } else {
    $i_salt = gen_salt(16);
  }

  if($i_rounds < 1000) {
    $i_rounds = 1000;
  } else if($i_rounds > 999999999) {
    $i_rounds = 999999999;
  }

  $i_salt = substr($i_salt, 016);

  //Undefine temp variables
  unset($i);
  unset($rounds);
  unset($salt);

  //Initialization done ... now calculate the hash ...
/**
  Implementation based on http://people.redhat.com/drepper/SHA-crypt.txt
*/


  //1+2+3
  $d_A = hash_init('sha512');
  hash_update($d_A, $password);
  hash_update($d_A, $i_salt);

  //4+5+6+7+8
  $d_B = hash_init('sha512');
  hash_update($d_B, $password);
  hash_update($d_B, $i_salt);
  hash_update($d_B, $password);
  $B = hash_final($d_B, true);

  //9+10
  for($i = strlen($password); $i >= strlen($B); $i -= strlen($B)) {
     hash_update($d_A, $B);
    }
  hash_update($d_A, substr($B, 0, $i));

  //11
  $i = strlen($password);
  while($i) {
    if($i&1) {
          hash_update($d_A, $B);
    } else {
          hash_update($d_A, $password);
    }
    $i >>= 1;
  }

  //12
  $A = hash_final($d_A, true);

  //13+14+15
  $d_DP = hash_init('sha512');
  for($i = strlen($password); $i; $i--) {
        hash_update($d_DP, $password);
    }
    $DP = hash_final($d_DP, true);

  //16
  $P = '';
  for($i = strlen($password); $i >= strlen($DP); $i -= strlen($DP)) {
     $P .= $DP;
    }
  $P .= substr($DP, 0, $i);

  //17+18+19
  $d_DS = hash_init('sha512');
  for($i = 16+ord($A[0]); $i; $i--) {
        hash_update($d_DS, $i_salt);
    }
    $DS = hash_final($d_DS, true);

  //20
  $S = '';
  for($i = strlen($i_salt); $i >= strlen($DS); $i -= strlen($DS)) {
     $S .= $DS;
    }
  $S .= substr($DS, 0, $i);

  //21
  for($round = 0; $round < $i_rounds; $round++) {
        //21a
        $d_C = hash_init('sha512');

    //21a+b+c
    if($round&1) {
      hash_update($d_C, $P);
    } else {
      hash_update($d_C, $A);
    }

    //21d
    if($round%3) {
      hash_update($d_C, $S);
    }
    //21e
    if($round%7) {
      hash_update($d_C, $P);
    }
    //21f+g
    if($round&1) {
      hash_update($d_C, $A);
    } else {
      hash_update($d_C, $P);
    }
    //21h
    $A = hash_final($d_C, true);
  }

  //22a
  $result = '$6$';

  //22b
  if($i_has_rounds || ($i_rounds != 5000)) {
    $result .= "rounds={$i_rounds}\$";
  }

  //22c+d
  $result .= $i_salt . '$';

  //22e
  //Encode digest bytes
  $tmp = crypt_sha512_encode($A);

  $result .= $tmp;
  return $result;
}

function crypt_sha512_encode($data){
    $chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  $pos = array(
       0 , 21 , 42,  22 , 43 ,  1,  44 ,  2 , 23,   3 , 24 , 45,
      25 , 46 ,  4,  47 ,  5 , 26,   6 , 27 , 48,  28 , 49 ,  7,
      50 ,  8 , 29,   9 , 30 , 51,  31 , 52 , 10,  53 , 11 , 32,
      12 , 33 , 54,  34 , 55 , 13,  56 , 14 , 35,  15 , 36 , 57,
      37 , 58 , 16,  59 , 17 , 38,  18 , 39 , 60,  40 , 61 , 19,
      62 , 20 , 41,  -1 , -1 , 63
        );

    $result = '';

    for($i = 0; $i < count($pos);) {
        $B2 = $pos[$i++];
        $B1 = $pos[$i++];
        $B0 = $pos[$i++];
        $B2 = $B2 < 0 ? 0 : ord($data[$B2]);
        $B1 = $B1 < 0 ? 0 : ord($data[$B1]);
        $B0 = $B0 < 0 ? 0 : ord($data[$B0]);

        $n = 4;
        if($pos[$i-3] < 0) {
            $n--;
        }
        if($pos[$i-2] < 0) {
            $n--;
        }

        $w = ($B2 << 16) + ($B1 << 8) + $B0;
        while($n--) {
            $result .= $chars[$w & 0x3F];
            $w >>= 6;
        }
    }

    return $result;
}

$tv = array(
  array( '$6$saltstring''Hello world!',
    '$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1' ),
  array( '$6$rounds=10000$saltstringsaltstring''Hello world!',
    '$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v.' ),
  array( '$6$rounds=5000$toolongsaltstring''This is just a test',
    '$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQzQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0' ),
  array( '$6$rounds=1400$anotherlongsaltstring',
    'a very much longer text to encrypt.  This one even stretches over morethan one line.',
    '$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wPvMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1' ),
  array( '$6$rounds=77777$short',
    'we have a short salt string but not a short password',
    '$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0gge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0' ),
  array( '$6$rounds=123456$asaltof16chars..''a short string',
    '$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1' ),
  array( '$6$rounds=10$roundstoolow''the minimum number is still observed',
    '$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1xhLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX.' )
);

foreach($tv as $tvd) {
    echo crypt_sha512($tvd[1], $tvd[0]) . "\n" . $tvd[2] . "\n<br/>\n";
}

?>


Und hier noch die fehlenden Funktionen zur Salt-Generierung:

ausblenden volle Höhe salt_api.php
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
<?

function gen_salt($length, $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./") {
  if($length < 1) {
    $length = 1;
  }

  $raw = random_getbytes($length);

  $lc = strlen($chars);
  $salt = '';
  $i = $length;
  while($i) {
    $salt .= $chars[ord($raw[--$i]) % $lc];
  }

  return $salt;
}

function gen_salt_des() {
  return gen_salt(2);
}

function gen_salt_des2() {
  return gen_salt(9);
}

function gen_salt_apr1() {
  return gen_salt(8);
}

function gen_salt_sha() {
  return gen_salt(16);
}

function random_getbytes($count) {
  if($count < 1) {
    $count = 1;
  }

  //Check for access to /dev/urandom
  if(is_readable('/dev/urandom')) {
    //We can read data from /dev/urandom: Use this!
    $fp = @fopen('/dev/urandom','rb');
    if ($fp !== FALSE) {
      $pr_bits .= @fread($fp,$count);
      @fclose($fp);
      return $pr_bits;
    }
  }

  //Check for mt_random support
  if(function_exists('mt_rand')) {
    $pr_bits = '';
    for ($i = 0; $i < $count; $i++) {
      $pr_bits .= chr(mt_rand(0,255));
    }
    return $pr_bits;
  }

  //Fallback to the internal PHP random number generator
  $pr_bits = '';
  for($i = 0; $i < $count; $i++) {
    $pr_bits .= chr(rand(0,255));
  }
  return $pr_bits;
}

?>


Dank trotzdem. Wer die Routinen nutzen möchte: Die Lizenz ist die gleiche wie für TMutexIPC von mir.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Do 01.01.09 21:20 
äh ja cool. Aber wieso nochmal genau hast du dir die Mühe gemacht? Ich steh auf dem Schlauch... :oops:

_________________
In the beginning was the word.
And the word was content-type: text/plain.
BenBE Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 01.01.09 22:07 
user profile iconmatze hat folgendes geschrieben Zum zitierten Posting springen:
äh ja cool. Aber wieso nochmal genau hast du dir die Mühe gemacht? Ich steh auf dem Schlauch... :oops:


Ich hab mir daher die Mühe gemacht, da SHA256-Crypt- und SHA512-Crypt-Hashes zur Speicherung von Passwörtern in PHP nicht in allen Versionen unterstützt werden, Verfahren wie DES\3DES-Crypt und MD5-Crypt allerdings auf Grund der geringen Hashlänge nicht mehr als sicher betrachtet werden können. Es gibt ferner zwar noch eine ganze Reihe anderer Verfahren (APR1 beim Apache z.B., MD5-Hashes [$1$] bei einigen Linux-Distries und Blowfish, diese sind aber im Wesentlichen von den Original-Crypts nur unterschiedlich abgedeckt.

Ziel war es hier, eine Crypt-Implementation in PHP für eigene Scripte zu schreiben, die weitestgehend unabhängig von der verwendeten PHP-Implementation ist, um auch beim Erzeugen der Hashes etwas mehr Flexibilität zu haben. Die Skripte werden später zum Schreiben von Config-Files benötigt, wo teilweise bestimmte Hashes gefordert sind.

Warum ich kein einfaches Salted MD5 implementiere: Da das jedes Programm anders macht; crypt_sha256/512 ist eine "standardisierte" Form, die aktuelle Versionen von crypt(3) unter Linux können; auf diese Art kann ich mit PHP-Skripten reibungslos diverse Password-Files wie z.B. htpasswd für'n Apache oder auch LDIF-Files schreiben.

Anmerkung: Die jetzige Implementation mit hash* benötigt zwar PHP 5.1.2+, das lässt sich aber durch Austausch einzelner Funktionsaufrufe auch auf ältere PHP-Versionen portieren (auch wenn ich das für meinen Einsatz-Zweck weniger brauch).

Ach ja: Eine Frage hätt ich dann noch:
Kennt jemand noch andre Hash-Formate (wenn möglich mit nem Link zur Beschreibung):
$1$ (MD5 Hashes
$2$ (Blowfish)
$2a$ (Blowfish, BSD-style)
$5$ (SHA256)
$6$ (SHA512)
$apr1$ (Apache 2 htpasswd file)
$H$ (phpBB3 Implementation of PHPass portable Hashes)
$P$ (PHPass portable Hashes)
13-char 3DES hashes (old Linux style)
20-char 3DES hashes (Extended 3DES hashes)

(ADie Liste sind die, von denen ich weiß, dass sie definiert sind; gibt's da noch weitere?

TIA.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
KenanSulayman
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Sa 03.01.09 01:43 
Titel: Reimplementation
Hallo BenBE!

Ich mag deine Art zu programmieren zwar nicht aber ich habe das Ganze akzeptabel als mögliche Implementation ausgearbeitet.

Folgendes würde ich auf jeden Fall wegschneiden:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
<?
    unset( $i ); // -> Wird nicht mehr verwendet, also unset nicht nötig.
    unset( $rounds ); // -> Wird nicht mehr verwendet, also unset nicht nötig.
    unset( $salt ); // -> Wird nicht mehr verwendet, also unset nicht nötig.
?>


Änderungen:
- { ~ } Teile bei If - Parts mit einer Zeile
+ Class -> Public Deklaration von [$rounds, $salt, $has_rounds]
- Namentliche Funktionsdeklaration verkürtzt -> [ crypt_sha512_encode ~ enc ]

Code:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
<?php
    class Sha512 {
        public $iterations = 5000;
        public $salt = '';
        public $rounds = false;
        
        public function crypt_sha512( $password, $salt = "" ) {
            $i_rounds = $this -> iterations;
            $i_salt = $this -> salt;
            $i_has_rounds = $this -> rounds;
            if ( !empty( $salt ) ) {
                if ( substr( $salt, 03 ) != '$6$' ) return false;
                
                $salt = substr( $salt, 3 );
                
                if ( strtolower( substr( $salt, 07 ) ) == 'rounds=' ) {
                    $i = strpos( $salt, '$' );
                    if ( false !== $i ) {
                        $s = substr( $salt, 7, $i - 7 );
                        $i_rounds = @( int )$s;
                        $i_has_rounds = true;
                        $salt = substr( $salt, $i + 1 );
                    }
                }
                $i = strpos( $salt, '$' );
                if ( false !== $i ) $salt = substr( $salt, 0, $i );
                $i_salt = $salt;
            } else {
                $i_salt = $this -> gen_salt( 16 );
            }
            if ( $i_rounds < 1000 ) {
                $i_rounds = 1000;
            } elseif ( $i_rounds > 999999999 ) {
                $i_rounds = 999999999;
            }
            $i_salt = substr( $i_salt, 016 );            
            
            $d_A = hash_init( 'sha512' );
            hash_update( $d_A, $password );
            hash_update( $d_A, $i_salt );
            
            $d_B = hash_init( 'sha512' );
            hash_update( $d_B, $password );
            hash_update( $d_B, $i_salt );
            hash_update( $d_B, $password );
            $B = hash_final( $d_B, true );
            
            for ( $i = strlen( $password ); $i >= strlen( $B ); $i -= strlen( $B ) ) {
                hash_update( $d_A, $B );
            }
            hash_update( $d_A, substr( $B, 0, $i ) );
            
            $i = strlen( $password );
            while ( $i ) {
                if ( $i & 1 ) {
                    hash_update( $d_A, $B );
                } else {
                    hash_update( $d_A, $password );
                }
                $i >>= 1;
            }
            
            $A = hash_final( $d_A, true );
            
            $d_DP = hash_init( 'sha512' );
            for ( $i = strlen( $password ); $i; $i-- ) {
                hash_update( $d_DP, $password );
            }
            $DP = hash_final( $d_DP, true );
            
            $P = '';
            for ( $i = strlen( $password ); $i >= strlen( $DP ); $i -= strlen( $DP ) ) {
                $P .= $DP;
            }
                $P .= substr( $DP, 0, $i );
            
            $d_DS = hash_init( 'sha512' );
            for ( $i = 16 + ord( $A[ 0 ] ); $i; $i-- ) {
                hash_update( $d_DS, $i_salt );
            }
            $DS = hash_final( $d_DS, true );
            
            $S = '';
            for ( $i = strlen( $i_salt ); $i >= strlen( $DS ); $i -= strlen( $DS ) ) {
                $S .= $DS;
            }
            $S .= substr( $DS, 0, $i );
            
            for ( $round = 0; $round < $i_rounds; $round++ ) {
                
                $d_C = hash_init( 'sha512' );
                
                if ( $round & 1 ) {
                    hash_update( $d_C, $P );
                } else {
                    hash_update( $d_C, $A );
                }
                
                if ( $round % 3 ) {
                    hash_update( $d_C, $S );
                }
                
                if ( $round % 7 ) {
                    hash_update( $d_C, $P );
                }
                
                if ( $round & 1 ) {
                    hash_update( $d_C, $A );
                } else {
                    hash_update( $d_C, $P );
                }
                
                $A = hash_final( $d_C, true );
            }
            
            $result = '$6$';
            
            if ( $i_has_rounds || ( $i_rounds != 5000 ) ) {
                $result .= "rounds={$i_rounds}\$";
            }
            
            $result .= $i_salt . '$';
            
            
            $tmp = $this -> enc( $A );
            $result .= $tmp;
            return $result;
        }
        public function enc( $data ) {
            $chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            $pos = array( 02142224314422332445254644752662748284975082993051315210531132123354345513561435153657375816591738183960406119622041, -1, -163 );
            $result = '';
            for ( $i = 0; $i < count( $pos ); ) {
                $B2 = $pos[ $i++ ];
                $B1 = $pos[ $i++ ];
                $B0 = $pos[ $i++ ];
                $B2 = $B2 < 0 ? 0 : ord( $data[ $B2 ] );
                $B1 = $B1 < 0 ? 0 : ord( $data[ $B1 ] );
                $B0 = $B0 < 0 ? 0 : ord( $data[ $B0 ] );
                $n = 4;
                if ( $pos[ $i - 3 ] < 0 ) $n--;
                if ( $pos[ $i - 2 ] < 0 ) $n--;
                $w = ( $B2 << 16 ) + ( $B1 << 8 ) + $B0;
                while ( $n-- ) {
                    $result .= $chars[ $w & 0x3F ];
                    $w >>= 6;
                }
            }
            return $result;
        }
        public function gen_salt( $length, $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./" ) {
            if ( $length < 1 or !is_numeric($length) ) $length = 1;
            $raw = $this -> random_getbytes( $length );
            $lc = strlen( $chars );
            $salt = '';
            $i = $length;
            while ( $i ) {
                $salt .= $chars[ ord( $raw[ --$i ] ) % $lc ];
            }
            return $salt;
        }
        public function random_getbytes( $count ) {
            if ( $count < 1  or !is_numeric($count) ) $count = 1;
            
            /* Unix capable, but what's up with windows ? */
        /*  if ( is_readable( '/dev/urandom' ) ) {
                $fp = @fopen( '/dev/urandom', 'rb' );
                if ( $fp !== false ) {
                    $pr_bits .= @fread( $fp, $count );
                    @fclose( $fp );
                    return $pr_bits;
                }
            }
            
            if ( function_exists( 'mt_rand' ) ) {
                $pr_bits = '';
                for ( $i = 0; $i < $count; $i++ ) {
                    $pr_bits .= chr( mt_rand( 0, 255 ) );
                }
                return $pr_bits;
            } */

            
            for ( $i = 0, $pr_bits = ''; $i < $count; $i++ ) $pr_bits .= chr( rand( 0255 ) );
            return $pr_bits;
        }
    }
    ($d = new Sha512) and print $d -> crypt_sha512('d');
    // ( ~ ) -> $6$GPZTBYUc59bCdW0K$eyiwALcCot7YIy2RzFn3RkSJW2iHp8mMobGzhKtKTpPrciqISoPtz3qRoQf6vU5znUGJ9y0WaH7sjbGaI7SzI/
?>


Wobei ich mich immer noch wundere: dass das um den Tod keine richtige Sha512 Ausgabe ist?

Arbeite lieber mal an einem richtigem Sha512 Algorithmus.

--
Kenan Sulayman
KurealCorporation inc.
Global Application Designer
BenBE Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 03.01.09 01:58 
Titel: Re: Reimplementation
user profile iconKenanSulayman hat folgendes geschrieben Zum zitierten Posting springen:
Hallo BenBE!

Ich mag deine Art zu programmieren zwar nicht aber ich habe das Ganze akzeptabel als mögliche Implementation ausgearbeitet.

Über Code-Formatierung kann man streiten.

user profile iconKenanSulayman hat folgendes geschrieben Zum zitierten Posting springen:
Folgendes würde ich auf jeden Fall wegschneiden:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
<?
    unset( $i ); // -> Wird nicht mehr verwendet, also unset nicht nötig.
    unset( $rounds ); // -> Wird nicht mehr verwendet, also unset nicht nötig.
    unset( $salt ); // -> Wird nicht mehr verwendet, also unset nicht nötig.
?>

Verwendet werden diese Variablen eben ja noch ;-) Zumindest $i. Die besagten Zeilen waren aber eh hauptsächlich zum Finden von Bugs (Gibt ne Warnung, wenn ich mich im unteren Teil vertan hätte).

Zudem hatte die Formatierung einen Sinn: Achte in meinem Source einmal auf die Kommentare. Da müsste Dir auffallen, dass das die Referenzen auf die Original-Implementierung laut Algo sind, d.h. die Kommentare geben an, was aus der Algorithmen-Beschreibung an der jeweiligen Stelle getan wird.

user profile iconKenanSulayman hat folgendes geschrieben Zum zitierten Posting springen:
Änderungen:
- { ~ } Teile bei If - Parts mit einer Zeile
+ Class -> Public Deklaration von [$rounds, $salt, $has_rounds]
- Namentliche Funktionsdeklaration verkürtzt -> [ crypt_sha512_encode ~ enc ]

Ist eh vorerst eine Grob-Implementation gewesen; wird im Ziel-Projekt, wo es mal eingebunden wird, auf jeden Fall als Klasse implementiert (mit noch ein paar andren Änderungen). Mir ging es hier erstmal hauptsächlich darum, die Implementierung an sich korrekt zu haben: Optimieren und Formatieren des Codes kann man dan immer noch.

Deine Variante des Codes find ich übrigens auf Grund der fehlenden Referenzierung der Spezifikation unübersichtlicher, auch wenn man i.d.R. lange Routinen eher splitten sollte.

user profile iconKenanSulayman hat folgendes geschrieben Zum zitierten Posting springen:
Wobei ich mich immer noch wundere: dass das um den Tod keine richtige Sha512 Ausgabe ist?

Ist auch nicht dazu gedacht, SHA512 an sich zu berechnen, sondern den (oben mehrfach verlinkten) Algorithmus zu Validierung von Passwörtern mit Hilfe von Unix-Style crypt_sha256\512-Hashes abzugleichen.

user profile iconKenanSulayman hat folgendes geschrieben Zum zitierten Posting springen:
Arbeite lieber mal an einem richtigem Sha512 Algorithmus.

Siehe die Funktionen sha256 und sha512 in meiner Implementation. Die machen genau das. die beiden crypt-Varianten berechnen Hashes unter Nutzung von SHA256\SHA512 analog dem, was crypt macht, wenn man $1$ (MD5) oder $2a$ (Blowfish) generiert. Siehe die PHP-Doku zu [url=php.net/crypt]crypt[/url] für mehr Details. Die genannten Routinen ergänzen dort nur (so Portabel wie möglich) die Nutzung weiterer Hash-Formate.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
KenanSulayman
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Sa 03.01.09 02:13 
Titel: Re: Reimplementation
Verstanden.

Wo hasst du deine Vorlage her ? / Sprich Ursprung der Definition des Algorithmus ?

--
Kenan Sulayman
KurealCorporation inc.
Global Application Designer
BenBE Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 03.01.09 02:15 
Titel: Re: Reimplementation
user profile iconKenanSulayman hat folgendes geschrieben Zum zitierten Posting springen:
Wo hasst du deine Vorlage her ? / Sprich Ursprung der Definition des Algorithmus ?

people.redhat.com/drepper/SHA-crypt.txt

(Lesen des ersten Posts, sowie meines Sources müsste Dir diesenLink eigentlich offenbart haben, denn da taucht dieser Link mehrfach auf).

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
KenanSulayman
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Sa 03.01.09 02:18 
Titel: Re: Reimplementation
Entschulding. Ich bin gerade etwas beschäftig, da* habe ich das doch tatsächlich übersehen ...

--
Kenan Sulayman
KurealCorporation inc.
Global Application Designer

P.s.: Schönes neues Jahr!