2

Google 検索の多くでここにたどり着いたことに気づいたので、おそらくあなたの適切な心を借りることができると思いました :)

私は、3 年次の学位論文の一環として、モバイル デバイス (およびログイン用の Web サイト) 用のワンタイム パスワード ジェネレーターに取り組んでいます。

org.bouncycastle.crypto.digests.MD5Digest ライブラリを使用して、(文字列ユーザー入力から) バイト配列を取得し、それを X 回ハッシュしています。これは、デイジー チェーン ハッシュ文字列またはランポート方式の暗号化とも呼ばれます。

私の問題は、文字列が一度ハッシュされると正しくハッシュされますが、新しいハッシュが再度ハッシュされると結果が正しくないということです。

以下のコードを参照してください。

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;
    }

どちらかだと思います。

  1. ダイジェストが正しいバイト配列を返さない
  2. Hex コンバーターはこれを誤って変換します

次の MD5 出力を持つ A のシークレットを使用してテストしています。

  1. 7fc56270e7a70fa81a5935b72eacbe29
  2. 8f28f2e7231860115d2a8cacba019dbe (これは 4cbd6d53280de25e04712c7434a70642 である必要があります)

事前にご協力いただきありがとうございます:)

ps PHP md5に対してチェックしていますが、これも問題になる可能性がありますか?

4

2 に答える 2

5

MD5 を値 0x41 (「A」) の 1 バイトで構成される入力に適用すると、16 バイトの出力が生成され、16 進数で出力すると、7fc56270e7a70fa81a5935b72eacbe29.

これらの16バイトにMD5 を適用する8f28f2e7231860115d2a8cacba019dbeと、 が得られ、それが得られます。

ここで、文字列 " "の ASCII エンコードである32 バイトの文字列に適用される MD5 を考えると、次のようになります。したがって、あなたの Java コードは問題なく (そのため)、PHP ベースのテスト コードに入力データを与える方法に混乱が生じていると思います。あなたはそれを「値 0x7f の 1 バイト、次に値 0xc5 の 1 バイト、そして...」と書いて考えますが、PHP コードはそれを「値 0x37 ('7' の ASCII コード) の 1 バイト、次に値 0x66 の 1 バイト ('f' の ASCII コード)、そして...".7fc56270e7a70fa81a5935b72eacbe294cbd6d53280de25e04712c7434a706427fc562...

Linux システムでは、これを試してください。

$ 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  -

補足として:

  • に注意してくださいOTP.getBytes()。ロケール依存の文字セットを使用して文字列をバイトに変換します。これは、システム構成に応じて、UTF-8、UTF-16、ISO-8859-1 などを使用し、通常は「システム言語」に関連付けられています。コードは同じ文字列に対して異なる動作をしますが、これはあまり良い考えではありません。代わりにOTP.getBytes("UTF-8")、ローカル構成に関係なく同じバイトを計算する which を使用してください。
  • ハッシュ ループには役に立たないマントラが含まれています。たとえば、決して使用しない 16 バイトの配列を割り当てます。
  • Java では、大文字で始まる変数名を持つことは不適切なコーディング スタイルと見なされます。学校のコンテキストでコードを表示する予定がある場合は、名前を に変更する必要がありHexますhex
  • halfByteが " " の結果として得られる場合& 0x0F、必ず 0 ~ 15 の値が含まれます。" 0 <= halfByte" テストは不要です。
于 2010-02-03T21:13:39.877 に答える
1

問題は、私の Java MD5 が PHP MD5 のように動作しないことでした。

基本的に(Javaで)バイト配列を取得して16進文字列に変換し、この文字列のバイトを取得して、16進バイト配列を使用するのではなく、MD5化するという問題の解決策を見つけました。以下の解決策を参照してください

結果については、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;
    }

投稿してくださった皆様、本当にありがとうございました!

于 2010-02-03T23:22:45.327 に答える