使用充气城堡的Java ME MD5字符串 - 不能多次哈希

And*_*ett 2 java md5 one-time-password java-me

我注意到我的很多谷歌搜索都把我带到了这里,所以我想也许我可以借用你的思想:)

作为我的三年级学位论文的一部分,我正在为移动设备(以及登录的网站)开发一次性密码生成器.

使用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;
    }
Run Code Online (Sandbox Code Playgroud)

我认为它要么;

  1. 摘要不返回正确的字节数组
  2. 十六进制转换器错误地转换它

我使用以下秘密进行测试:A具有以下MD5输出:

  1. 7fc56270e7a70fa81a5935b72eacbe29
  2. 8f28f2e7231860115d2a8cacba019dbe(这应该是4cbd6d53280de25e04712c7434a70642)

非常感谢您的帮助:)

ps我正在检查PHP md5这可能是一个问题吗?

Tho*_*nin 5

MD5应用于由单个字节值0x41('A')组成的输入时,产生一个16字节的输出,当以十六进制打印时,输出为7fc56270e7a70fa81a5935b72eacbe29.

如果你在这16个字节上应用MD5 ,你应该得到8f28f2e7231860115d2a8cacba019dbe,这就是你得到的.

现在,如果你认为MD5应用于一个32字节的字符串,这是字符串" 7fc56270e7a70fa81a5935b72eacbe29" 的ASCII编码,那么这就产生了4cbd6d53280de25e04712c7434a70642.因此,我认为您的Java代码很好(为此),您的困惑来自于如何将输入数据提供给基于PHP的测试代码.您编写7fc562...并将其视为"值为0x7f的一个字节,然后是值为0xc5的一个字节,然后......"但PHP代码将其视为"值为0x37的一个字节("7"的ASCII代码),那么一个字节的值为0x66('f'的ASCII码),然后......".

在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  -
Run Code Online (Sandbox Code Playgroud)

作为附注:

  • 要小心OTP.getBytes().它通过使用依赖于语言环境的字符集将字符串转换为字节.这将使用UTF-8,UTF-16,ISO-8859-1,......取决于系统配置,通常与"系统语言"相关联.您的代码将对同一个字符串采取不同的行为,这很少是一个好主意.相反,使用OTP.getBytes("UTF-8")哪个将计算相同的字节,而不管本地配置如何.
  • 你的哈希循环包括无用的咒语.例如,您分配一个16字节的数组,您永远不会使用它.
  • Java中的编码风格被认为是以大写字母开头的变量名称.如果你打算出在学校范围内的代码,那么你应该重新命名Hexhex.
  • halfByte作为" & 0x0F" 的结果获得时,它必然包含0到15之间的值." 0 <= halfByte"测试是不必要的.