反身哈希?

时间:2011-01-28 00:50:58

标签: algorithm hash

是否有一类散列算法,无论是理论上的还是实际的,根据下面的定义,类中的算法可能被认为是“反身”:

  • hash1 = algo1(“输入文字1”)
  • hash1 = algo1(“输入文本1”+ hash1)

+运算符可能是串联或任何其他指定的操作,以将输出(hash1)组合回输入(“输入文本1”),以便算法(algo1)将产生完全相同的结果。即输入和输入+输出上的冲突。 +运算符必须组合两个输入的全部,算法可能不会丢弃部分输入。

该算法必须在输出中产生128位熵。 它可能(但不一定)在加密方面难以将输出反转回一个或两个可能的输入。

我不是数学家,但一个好的答案可能包括为什么这类算法不存在的证据。然而,这不是一个抽象的问题。我真的很想在我的系统中使用这样的算法,如果确实存在的话。

5 个答案:

答案 0 :(得分:1)

当然,这是一个微不足道的:

def algo1(input):
    sum = 0
    for i in input:
        sum += ord(i)
    return chr(sum % 256) + chr(-sum % 256)

连接结果,“哈希”不会改变。当你可以反转哈希时,很容易想出类似的东西。

答案 1 :(得分:1)

ephemiat's answer的基础上,我认为你可以这样做:

选择您喜欢的对称密钥块密码(例如:AES)。具体来说,假设它在128位块上运行。对于给定密钥K,分别用Enc(K,块)和Dec(K,块)表示加密函数和解密函数,因此block = Dec(K,Enc(K,block))= Enc(K,十二月(K,街区))。

将输入分为128位块数组(必要时填充)。您可以选择固定密钥K,也可以将其作为哈希输入的一部分。在下文中,我们假设它是固定的。

def hash(input):
   state = arbitrary 128-bit initialization vector
   for i = 1 to len(input) do
      state = state ^ Enc(K, input[i])
   return concatenate(state, Dec(K, state))

此函数返回256位散列。通过一个警告来验证它是否满足“反身性”条件应该不是太难 - 在连接散列之前必须将输入填充到整数个128位块。换句话说,代替最初指定的hash(input)= hash(input + hash(input)),我们有hash(input)= hash(input'+ hash(input)),其中input'只是填充输入。我希望这不是太麻烦。

答案 2 :(得分:1)

是的,您可以使用CRC获得此效果。

您需要做的是:

  1. 实现一种算法,该算法将找到从一个给定状态(N位CRC累加器)到另一个给定状态的N个输入位序列。
  2. 以正常方式计算输入的CRC。注意最终状态(称之为A)
  3. 使用(1)中实现的函数,找到从A到A的比特序列。此序列是您的哈希码。您现在可以将其附加到输入。
  4. [Initial state] >- input string -> [A] >- hash -> [A] ...
    

    Here is one way to find the hash。 (注意:CRC32示例中的数字有误,但算法有效。)

    这是Java中的一个实现。注意:我使用的是32位CRC(小于你指定的64位),因为它是在标准库中实现的,但是使用第三方库代码可以轻松地将其扩展为更大的哈希值。

    public static byte[] hash(byte[] input) {
        CRC32 crc = new CRC32();
        crc.update(input);
        int reg = ~ (int) crc.getValue();
        return delta(reg, reg);
    }
    
    public static void main(String[] args) {
        byte[] prefix = "Hello, World!".getBytes(Charsets.UTF_8);
    
        System.err.printf("%s => %s%n", Arrays.toString(prefix), Arrays.toString(hash(prefix)));
    
        byte[] suffix = hash(prefix); 
        byte[] combined = ArrayUtils.addAll(prefix, suffix);
    
        System.err.printf("%s => %s%n", Arrays.toString(combined), Arrays.toString(hash(combined)));
    }
    
    private static byte[] delta(int from, int to) {
        ByteBuffer buf = ByteBuffer.allocate(8);
        buf.order(ByteOrder.LITTLE_ENDIAN);
        buf.putInt(from);
        buf.putInt(to);
        for (int i = 8; i-- > 4;) {
            int e = CRCINVINDEX[buf.get(i) & 0xff];
            buf.putInt(i - 3, buf.getInt(i - 3) ^ CRC32TAB[e]);
            buf.put(i - 4, (byte) (e ^ buf.get(i - 4)));
        }
        return Arrays.copyOfRange(buf.array(), 0, 4);
    }
    private static final int[] CRC32TAB = new int[0x100];
    private static final int[] CRCINVINDEX = new int[0x100];
    static {
        CRC32 crc = new CRC32();
        for (int b = 0; b < 0x100; ++ b) {
            crc.update(~b);
            CRC32TAB[b] = 0xFF000000 ^ (int) crc.getValue();
            CRCINVINDEX[CRC32TAB[b] >>> 24] = b;
            crc.reset();
        }
    }
    

答案 3 :(得分:0)

好吧,我可以告诉你,你不会得到不存在的证据。这是一个例子:

operator +(a,b):计算a的64位散列,b的64位散列,并连接位串,返回128位散列。

algo1:对于某个128位值,忽略最后64位并计算前64位的一些散列。

非正式地,任何产生第一个运算符的algo1作为其第一步都可以。也许并不像你想要的那样有趣,但它符合要求。它也不是没有现实世界的例子。许多密码哈希算法会截断它们的输入。

答案 4 :(得分:0)

我很确定这样一个“反身散列”函数(如果它确实存在于多个微不足道的意义上)在正常意义上不会是一个有用的散列函数。

对于“普通”反身散列函数的示例:

    int hash(Object obj) { return 0; }