2 Stimmen

Java ME MD5-String mit Bouncy Castle - kann nicht mehrfach hashen

Ich habe bemerkt, dass viele meiner Google-Suchen mich hierher geführt haben, also dachte ich, ich könnte mir vielleicht Ihre treffenden Gedanken ausleihen :)

Im Rahmen meiner Dissertation im dritten Studienjahr arbeite ich an einem Generator für ein Einmalpasswort für ein mobiles Gerät (sowie für eine Website zum Einloggen).

Mit der org.bouncycastle.crypto.digests.MD5Digest Bibliothek nehme ich ein Byte-Array (aus einer Zeichenfolge Benutzereingabe) dann Hashing es X Anzahl von Zeiten. Dies ist auch als Daisy-Chaining Hash-Strings oder Lamports Methode der Verschlüsselung bekannt.

Mein Problem ist, dass, wenn die Zeichenfolge einmal gehasht wird, dann es richtig hasht es, jedoch wenn der neue Hash erneut gehasht wird das Ergebnis falsch ist.

Siehe Code unten:

private String generateHash(String OTP, int loopNum)
{
      byte[] secretBytes = OTP.getBytes();

      for (int x = 0; x < loopNum; x++)
      {
          byte[] tempStore = new byte[16];
          tempStore = hash(secretBytes);
          secretBytes = tempStore;
      }

      return convertToHex(secretBytes);
}

public byte[] hash(byte[] secretBytes)
{
        org.bouncycastle.crypto.digests.MD5Digest digest = new org.bouncycastle.crypto.digests.MD5Digest();

        digest.reset();

        // Update MD5 digest with user secret in byte format
        digest.update(secretBytes, 0, secretBytes.length);

        // get length of digest to initialise new md5 byte array
        int length = digest.getDigestSize();

        // create md5 byte array using length
        byte[] md5 = new byte[length];

        // calculate MD5 hash, using md5 byte array, 0 for buffer offset
        digest.doFinal(md5, 0);

        return md5;
}

private static String convertToHex(byte[] data) {
        StringBuffer buf = new StringBuffer();
        String Hex;
        String formattedHex;
        for (int i = 0; i < data.length; i++) {
            int halfbyte = (data[i] <<< 4) & 0x0F;
            int two_halfs = 0;
            do {
                if ((0 <= halfbyte) && (halfbyte <= 9))
                    buf.append((char) ('0'  + halfbyte));
                else
                    buf.append((char) ('a'+  (halfbyte - 10)));
                halfbyte = data[i] & 0x0F;
            } while(two_halfs++ < 1);
        }

        Hex = buf.toString();

        formattedHex = "\n"  + Hex.substring(0, 4) +  " " + Hex.substring(4, 8) + " " + Hex.substring(8, 12) + " "
               + Hex.substring(12, 16) +  " " + Hex.substring(16, 20) +  " "  +Hex.substring(20, 24) + " "
               + Hex.substring(24, 28) +  " " + Hex.substring(28, 32);
        return formattedHex;
    }

Ich denke, es ist entweder;

  1. Der Digest gibt kein korrektes Byte-Array zurück
  2. Der Hex-Konverter konvertiert dies fälschlicherweise

Ich teste mit dem Geheimnis von: A das die folgenden MD5-Ausgaben hat:

  1. 7fc56270e7a70fa81a5935b72eacbe29
  2. 8f28f2e7231860115d2a8cacba019dbe (dies sollte 4cbd6d53280de25e04712c7434a70642 sein)

Vielen Dank für Ihre Hilfe im Voraus :)

p.s. Ich überprüfe es gegen ein PHP md5 könnte dies auch ein Problem sein?

5voto

Thomas Pornin Punkte 70790

Wird MD5 auf eine Eingabe angewandt, die aus einem einzigen Byte mit dem Wert 0x41 (einem "A") besteht, ergibt sich eine 16-Byte-Ausgabe, die in hexadezimaler Darstellung wie folgt lautet 7fc56270e7a70fa81a5935b72eacbe29 .

Wenn Sie MD5 auf diese Daten anwenden 16 Bytes, sollten Sie erhalten 8f28f2e7231860115d2a8cacba019dbe und das ist es, was Sie bekommen.

Betrachtet man nun die Anwendung von MD5 auf eine 32 Byte Zeichenkette, die die ASCII-Kodierung der Zeichenkette " 7fc56270e7a70fa81a5935b72eacbe29 ", dann ergibt dies 4cbd6d53280de25e04712c7434a70642 . Ich denke also, dass Ihr Java-Code in Ordnung ist (dafür) und dass Ihre Verwirrung daher rührt, wie Sie die Eingabedaten an Ihren PHP-basierten Testcode übergeben. Sie schreiben 7fc562... und Sie denken darüber als "ein Byte mit dem Wert 0x7f, dann ein Byte mit dem Wert 0xc5, dann...", aber der PHP-Code nimmt es als "ein Byte mit dem Wert 0x37 (ASCII-Code für eine '7'), dann ein Byte mit dem Wert 0x66 (ASCII-Code für ein 'f'), dann...".

Auf einem Linux-System versuchen Sie dies:

$ printf A | md5sum
7fc56270e7a70fa81a5935b72eacbe29  -
$ printf 7fc56270e7a70fa81a5935b72eacbe29 | md5sum
4cbd6d53280de25e04712c7434a70642  -
$ printf "\x7f\xc5\x62\x70\xe7\xa7\x0f\xa8\x1a\x59\x35\xb7\x2e\xac\xbe\x29" | md5sum
8f28f2e7231860115d2a8cacba019dbe  -

Als Randnotizen:

  • Seien Sie vorsichtig mit OTP.getBytes() . Es wandelt eine Zeichenkette in Bytes um, indem es den lokalabhängigen Zeichensatz verwendet. Dabei wird UTF-8, UTF-16, ISO-8859-1,... verwendet, je nach Systemkonfiguration, die normalerweise an die "Systemsprache" gebunden ist. Ihr Code wird auf die gleiche Zeichenkette unterschiedlich reagieren, was selten eine gute Idee ist. Verwenden Sie stattdessen OTP.getBytes("UTF-8") die unabhängig von der lokalen Konfiguration die gleichen Bytes berechnet.
  • Ihre Hash-Schleife enthält nutzlose Mantras. Zum Beispiel weisen Sie ein 16-Byte-Array zu, das Sie nie verwenden.
  • In Java gilt es als schlechter Programmierstil, einen Variablennamen mit einem Großbuchstaben beginnen zu lassen. Wenn Sie vorhaben, Ihren Code in einem schulischen Kontext zu zeigen, sollten Sie ihn umbenennen Hex in hex .
  • Wenn halfByte erhält man als Ergebnis einer " & 0x0F ", dann enthält sie zwangsläufig einen Wert zwischen 0 und 15. Die " 0 <= halfByte "Test ist unnötig.

1voto

Andy Garbett Punkte 31

Vielen Dank für Ihre Hilfe. Das Problem war, dass sich mein Java MD5 nicht wie ein php MD5 verhielt.

Ich fand eine Lösung für das Problem, die im Grunde (in Java) nehmen Sie die Byte-Array und konvertieren Sie es in eine Hex-String und DANN erhalten die Bytes für diese Zeichenfolge, die dann MD5'd anstatt mit dem un hex'd Byte-Array. Siehe Lösungen unten

Das Ergebnis ist im Folgenden dargestellt: http://forums.sun.com/thread.jspa?forumID=9&threadID=718781

static String byteArrayToHexString(byte byteValues[]) {
        byte singleChar = 0;
        if (byteValues == null || byteValues.length <= 0)
            return null;

        String entries[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                "a", "b", "c", "d", "e", "f" };

        StringBuffer out = new StringBuffer(byteValues.length * 2);

        for (int i = 0; i < byteValues.length; i++) {
            singleChar = (byte) (byteValues[i] & 0xF0);
            singleChar = (byte) (singleChar >>> 4);
            // shift the bits down
            singleChar = (byte) (singleChar & 0x0F);
            out.append(entries[(int) singleChar]); 
            singleChar = (byte) (byteValues[i] & 0x0F); 
            out.append(entries[(int) singleChar]);
        }
        String rslt = new String(out);
        return rslt;
    }

Vielen Dank an alle, die gepostet haben, ich kann euch nicht genug danken!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X