Java ME строка MD5 с использованием надувного замка - не может хэшироваться несколько раз - PullRequest
2 голосов
/ 03 февраля 2010

Я заметил, что многие из моих поисков в Google привели меня сюда, поэтому я подумал, что, возможно, смогу позаимствовать ваши умные способности :)

Я работаю над генератором одноразовых паролей для мобильного устройства (а также веб-сайт для входа в систему) как часть моей дипломной работы на третьем курсе.

Используя библиотеку org.bouncycastle.cigpto.digests.MD5Digest, я беру массив байтов (из пользовательского ввода строки), затемхэширование X разЭто также известно как цепочка хеш-строк с последовательным подключением или метод шифрования lamports.

Моя проблема заключается в том, что если строка хешируется один раз, то она правильно хешируется, однако, если новый хэш хэшируется снова, результат неверен.

См. Код ниже:

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. Шестнадцатеричный преобразователь неправильно преобразует это

Я тестирую с использованием секрета: A, который имеет следующие выходы MD5:

  1. 7fc56270e7a70fa81a5935b72eacbe29
  2. 8f28f2e7231860115d2a8beba4cbd6d53280de25e04712c7434a70642)

Большое спасибо за вашу помощь заранее:)

ps Я проверяю это на PHP md5, это также может быть проблемой?

Ответы [ 2 ]

5 голосов
/ 04 февраля 2010

MD5 при применении к входу, состоящему из одного байта со значением 0x41 ('A'), дает 16-байтовый вывод, который при печати в шестнадцатеричном формате равен 7fc56270e7a70fa81a5935b72eacbe29.

Если вы примените MD5 к этим 16 байтам, вы должны получить 8f28f2e7231860115d2a8cacba019dbe, и это то, что вы получите.

Теперь, если вы считаете, что MD5 применяется к 32-байтовой строке, которая является кодировкой ASCII строки символов "7fc56270e7a70fa81a5935b72eacbe29", то это дает 4cbd6d53280de25e04712c7434a70642. Поэтому я думаю, что ваш Java-код подходит (для этого), и что ваша путаница возникает из-за того, как вы передаете входные данные в свой тестовый код на основе PHP. Вы пишете 7fc562... и думаете об этом как «один байт значения 0x7f, затем один байт значения 0xc5, затем ...», но код PHP принимает его как «один байт значения 0x37 (ASCII-код для '7 '), затем один байт значения 0x66 (ASCII-код для' f '), затем ... ".

В системе 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"), который будет вычислять одни и те же байты независимо от локальной конфигурации.
  • Ваш хэш-цикл включает в себя бесполезные мантры. Например, вы выделяете 16-байтовый массив, который вы никогда не используете.
  • В Java считается плохим стилем кодирования, когда имя переменной начинается с заглавной буквы. Если вы планируете показывать свой код в школьном контексте, вам следует переименовать Hex в hex.
  • Если halfByte получено в результате "& 0x0F", тогда оно обязательно содержит значение от 0 до 15. Тест "0 <= halfByte" не требуется.
1 голос
/ 04 февраля 2010

Большое спасибо всем за помощь, проблема была в том, что мой java md5 не вел себя как php MD5.

Я нашел решение проблемы, которое в основном (в Java) берет массив байтов и преобразует его в шестнадцатеричную строку, и ТОГДА получает байты для этой строки, которая затем MD5-вместо, а не байтом un hex массив. Смотрите решения ниже

См. Следующий результат: 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;
    }

Большое спасибо всем, кто написал, не могу сказать спасибо!

...