使用 bouncy caSTLe 的 Java ME MD5 字符串 - 不能多次散列

标签 java java-me md5 one-time-password

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

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

使用 org.bouncycaSTLe.crypto.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. 十六进制转换器错误地转换了它

我正在使用以下 secret 进行测试:A 具有以下 MD5 输出:

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

非常感谢您的提前帮助:)

附注我正在根据 PHP md5 检查它这是否也是一个问题?

最佳答案

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  -

作为旁注:

  • 警惕OTP.getBytes() .它使用依赖于语言环境的字符集将字符串转换为字节。这将使用 UTF-8、UTF-16、ISO-8859-1,...取决于系统配置,通常与“系统语言”相关联。您的代码将对同一个字符串执行不同的操作,这很少是一个好主意。相反,使用 OTP.getBytes("UTF-8")无论本地配置如何,它将计算相同的字节。
  • 您的哈希循环包含无用的咒语。例如,您分配了一个 16 字节的数组,但您从未使用过它。
  • 在 Java 中,变量名以大写字母开头被认为是糟糕的编码风格。如果您计划在学校环境中展示您的代码,那么您应该重命名 Hex进入hex .
  • 何时halfByte作为“& 0x0F”的结果获得,那么它必然包含 0 到 15 之间的值。“0 <= halfByte”测试是不必要的。

关于使用 bouncy caSTLe 的 Java ME MD5 字符串 - 不能多次散列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2194222/

相关文章:

Java Google 数据存储异步调用

java - Jayway JsonPath查询获取所需的json格式

java - j2me导入外部jar : what classpath?

java - 在 J2ME Canvas 上显示格式化文本

ubuntu - bash/ubuntu 中数百万个字符串的快速 md5sum

gwt - GWT中的post token是如何生成的?

java - 还有其他方法可以用 Intent 传递复杂对象吗?

java - Android:显示多个街景(Google Maps Api)

java - 引用不存在的类/方法的动态加载类何时在 Java 中失败?

c++ - Qt如何让应用程序获取自身的md5校验和