【问题标题】:How to design a sequential hash-like function如何设计一个顺序哈希函数
【发布时间】:2012-04-05 22:35:18
【问题描述】:

我想开发类似于 jsfiddle 的东西,用户可以在其中输入一些数据,然后“保存”它并获得一个独特的随机 url 来加载该数据。

我不想让保存按顺序进行,因为我不希望任何人获取我的所有条目,因为有些条目可能是私人的。但是在服务器上我想按顺序保存它。

是否有一种函数或技术可以将数字转换为具有 4 个字符的散列,在 (62 * 62 * 62 * 62 === 14776336) 条目之前没有任何冲突?

例如,服务器上的第一个条目将在服务器上命名为1,但用户命名为iUew3,下一个条目将在服务器上命名为2,但用户命名为ueGR...

编辑:我不确定这是否很明显,但这个类似哈希的函数需要是可逆的,因为当用户请求 ueGR 时,服务器需要知道将其服务器文件 2

【问题讨论】:

  • 如果我这样做,那么我可能会使用不同的编程语言,因此可以使用 the Crypt::Skip32::Base32Crockford module,它表示 让您拥有可以安全使用的数字数据库记录 ID在 URL 中,不会让用户看到您有多少条记录或让他们在记录之间向前或向后跳转。不过源代码是可用的,因此您可以根据需要将该算法移植到 PHP。
  • 为什么需要它是可逆的?只需将生成的哈希与 id 和您的完成一起存储即可。
  • @Yoshi:我没有使用数据库
  • 哦,那我猜你得找一个 crypt 函数(就像 Quentin 建议的那样)而不是一个散列函数。
  • 哈希函数根据定义是不可逆的。

标签: php algorithm hash


【解决方案1】:

可以这样做,但我建议使用 64 个字符,因为这样会更容易。 4 个 6 位字符 = 24 位。

结合使用这些:

  • 位重新排序
  • 与数字异或
  • 将其放入 24 位最大长度 LFSR 并执行几个循环。

强烈推荐使用 LFSR,因为它可以很好地进行加扰。其余的都是可选的。所有这些操作都是可逆的,并保证每个输出都是唯一的。

当您计算“混洗”数字时,只需将其打包为二进制字符串并使用base64_encode 对其进行编码。

对于解码,只需执行这些操作的逆操作。

样本(2^24 长的唯一序列):

function lfsr($x) {
    return ($x >> 1) ^ (($x&1) ? 0xe10000 : 0);
}
function to_4($x) {
    for($i=0;$i<24;$i++)
        $x = lfsr($x);
    $str = pack("CCC", $x >> 16, ($x >> 8) & 0xff, $x & 0xff);
    return base64_encode($str);
}

function rev_lfsr($x) {
    $bit = $x & 0x800000;
    $x = $x ^ ($bit ? 0xe10000 : 0);
    return ($x << 1) + ($bit ? 1 : 0);
}
function from_4($str) {
    $str = base64_decode($str);
    $x = unpack("C*", $str);
    $x = $x[1]*65536 + $x[2] * 256 + $x[3];
    for($i=0;$i<24;$i++)
        $x = rev_lfsr($x);
    return $x;
}

for($i=0; $i<256; $i++) {
    $enc = to_4($i);
    echo $enc . " " . from_4($enc) . "\n";
}

输出:

AAAA 0
kgQB 1
5ggD 2
dAwC 3
DhAH 4
nBQG 5
6BgE 6
ehwF 7
HCAO 8
jiQP 9
+igN 10
aCwM 11
EjAJ 12
gDQI 13
9DgK 14
ZjwL 15
OEAc 16
qkQd 17
3kgf 18
TEwe 19
NlAb 20
pFQa 21
0FgY 22

...

注意:对于 URL,将 + 和 / 替换为 - 和 _。

注意:虽然这可行,但对于像您这样的简单场景,创建随机文件名可能更容易,直到它不存在。没有人关心条目的数量。

【讨论】:

  • @Khorvath。这是一个很好的解决方案!是否可以将这些函数以与 YouTube URL 中 v $_GET 变量中包含的视频 ID 类似的方式缩放这些函数以形成一个 11 字符串编码的 ID,即youtube.com/watch?v=RArlg6HeZZM 中的 RArlg6HeZZM?
  • @BarryBeerman:是的,这是可能的。适用于任何实用尺寸。不过,您必须稍微更改一下代码。维基百科文章链接了这个:xilinx.com/support/documentation/application_notes/xapp052.pdf 它有解决方案,可以解决最大长度为 168 位的 LFSR 抽头。
  • @Khorvath:太完美了。如果你有机会,你能用代码示例回答这个问题stackoverflow.com/questions/18365607/…,以便我接受吗?再次感谢您的帮助。
  • @Khorvath:如果有帮助,我可以添加赏金。我刚刚看到很多尝试创建类似于 YouTube 的视频 ID 加密的算法,而您的方法无疑是最好的。
【解决方案2】:

在我看来,如果你还在服务器上保留save time of entry,你可以生成一个哈希函数。 hash = func(id, time) 但只有 hash = func(id) 会很容易解决

【讨论】:

    【解决方案3】:

    这是我实现它的方式。这是 save.php 文件(有人可以告诉我其中是否有任何设计缺陷):

    <?php
    
    $index = file_get_contents('saves/data/placeholder');
    $index++;
    file_put_contents('saves/data/placeholder', $index);
    
    $string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    do {
        $hash = $string[rand(0, 61)] . $string[rand(0, 61)] . $string[rand(0, 61)] . $string[rand(0, 61)];
    } while (file_exists('saves/' . $hash));
    
    file_put_contents('saves/' . $hash, $index);
    file_put_contents('saves/data/' . $index, $_REQUEST['data']);
    
    echo $hash;
    
    ?>
    

    这里是 load.php:

    <?php
    
    if (!file_exists('saves/' . $_REQUEST['file'])) {
        file_put_contents('saves/data/log', 'requested saves/' . $_REQUEST['file'] . "\n", FILE_APPEND);
        die();
    }
    $file_pointer = file_get_contents('saves/' . $_REQUEST['file']);
    
    if (!file_exists('saves/data/' . $file_pointer)) {
        file_put_contents('saves/data/log', 'requested saves/data/' . $file_pointer . 'from ' . $_REQUEST['file'] . "\n", FILE_APPEND);
        die();
    }
    echo file_get_contents('saves/data/' . $file_pointer);
    
    ?>
    

    希望这对其他人有所帮助。

    【讨论】:

      【解决方案4】:

      这是一组奇怪的约束。我经常使用 MD5 校验和从数据中生成唯一的 URL。如果用户还没有数据,他们就无法猜测 URL。

      我确实理解不想使用数据库 - 如果您以前从未使用过数据库,那么学习曲线可能会有点陡峭。

      我不明白“在服务器上按顺序存储东西”的限制。如果您需要知道创建哈希的顺序,我只需将该信息放在单独的文件中即可。您可能需要进行文件锁定或其他一些技巧,以确保您可以将哈希增量附加到该文件。

      如果您想要短 URL,您可以采用 MD5 校验和的前缀,也可以采用 CRC-32 和 base64 对其进行编码。两者都会以相当高的概率为您提供唯一的 URL。

      【讨论】:

      • 最后一段是一个不好的建议,你可以用它来制造冲突。
      • @KarolyHorvath,我知道,但 OP 指定了短 URL。实际上,我在 CRC-32 校验和方面取得了很好的成功。碰撞的概率很小。但是当我想要接近保证的东西时,我只使用完整的 MD5 并使用长 URL
      【解决方案5】:

      这是一个与 bcmath 一起工作的可逆库
      http://blog.kevburnsjr.com/php-unique-hash

      【讨论】:

        【解决方案6】:

        这真的是不可逆的。唯一的方法(url 缩短器和 jsfiddle 使用的方法)是将生成的哈希(实际上是摘要)存储在某种表/数据结构中,然后*在检索时查找。

        为什么会这样?

        通过,例如128 个字符的数据 → 4 个可见字符摘要,您会丢失很多数据。
        你不能把剩下的数据存储在这4个字节之间的神奇裂缝中,没有。

        【讨论】:

        • “将一个数字转换为具有 4 个字符的哈希,直到 (62 * 62 * 62 * 62 === 14776336) 个条目没有任何冲突” - 不会丢失数据。
        猜你喜欢
        • 2010-10-18
        • 2011-07-21
        • 2011-03-26
        • 2017-12-26
        • 2017-10-28
        • 2013-01-23
        • 2010-10-12
        • 2014-03-30
        • 1970-01-01
        相关资源
        最近更新 更多