【问题标题】:How to customize the output of the Postgres Pseudo Encrypt function?如何自定义 Postgres Pseudo Encrypt 函数的输出?
【发布时间】:2015-06-07 00:58:38
【问题描述】:

我想使用在 StackOverflow 上多次提到的 pseudo_encrypt 函数让我的 ID 看起来更随机:https://wiki.postgresql.org/wiki/Pseudo_encrypt

我如何自定义它以只为我输出唯一的“随机”数字。我在某处读到您可以更改 1366.0 常量,但我不想对我的 ID 承担任何风险,因为任何潜在的 ID 重复都会导致重大问题。

我真的不知道每个常量实际上是做什么的,所以我不想弄乱它,除非我得到一些指导。有谁知道我可以安全地更改哪些常量?

这里是:

CREATE OR REPLACE FUNCTION "pseudo_encrypt"("VALUE" int) RETURNS int     IMMUTABLE STRICT AS $function_pseudo_encrypt$
DECLARE
l1 int;
l2 int;
r1 int;
r2 int;
i int:=0;
BEGIN
    l1:= ("VALUE" >> 16) & 65535;
    r1:= "VALUE" & 65535;
    WHILE i < 3 LOOP
        l2 := r1;
        r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;
        r1 := l2;
        l1 := r2;
        i := i + 1;
END LOOP;
RETURN ((l1::int << 16) + r1);
END;
$function_pseudo_encrypt$ LANGUAGE plpgsql;

对于 bigint 的

CREATE OR REPLACE FUNCTION "pseudo_encrypt"("VALUE" bigint) RETURNS bigint IMMUTABLE STRICT AS $function_pseudo_encrypt$
DECLARE
l1 bigint;
l2 bigint;
r1 bigint;
r2 bigint;
i int:=0;
BEGIN
    l1:= ("VALUE" >> 32) & 4294967295::bigint;
    r1:= "VALUE" & 4294967295;
    WHILE i < 3 LOOP
        l2 := r1;
        r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767*32767)::bigint;
        r1 := l2;
        l1 := r2;
        i := i + 1;
    END LOOP;
RETURN ((l1::bigint << 32) + r1);
END;
$function_pseudo_encrypt$ LANGUAGE plpgsql;

【问题讨论】:

    标签: postgresql encryption


    【解决方案1】:

    替代解决方案:使用不同的密码

    其他密码函数现在可以在 postgres wiki 上使用。它们会明显变慢,但除此之外,它们更适合生成定制的随机外观系列的唯一数字。

    对于 32 位输出,Skip32 in plpgsql 将使用 10 字节宽的密钥加密其输入,因此您只需选择自己的密钥即可拥有自己的特定排列(2^32 唯一值的特定顺序)会出来)。

    对于 64 位输出,XTEA in plpgsql 的作用类似,但使用 16 字节宽的密钥。

    否则,只自定义pseudo_encrypt,见下文:

    关于pseudo_encrypt的实现说明:

    这个函数有3个属性

    • 输出值的全局唯一性
    • 可逆性
    • 伪随机效应

    第一个和第二个属性来自 Feistel 网络,正如 @CodesInChaos 的回答中已经解释的那样,它们不依赖于这些常量的选择:1366 以及 150889714025

    确保在更改 f(r1) 时它保持数学意义上的函数,即 x=y 意味着 f(x)=f(y),或者换句话说,相同的输入必须始终产生相同的输出。打破这一点将打破单一性。

    这些常数和f(r1) 的公式的目的是产生相当好的伪随机效应。使用 postgres 内置的random() 或类似方法是不可能的,因为它不是如上所述的数学函数。

    为什么是这些任意常数?在这部分函数中:

    r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;
    

    公式和值 1366150889714025 来自 C 中的数值配方(1992,William H.Press,第 2 版),第 7 章:随机数字,特别是第 284 和 285 页。 这本书不能直接在网络上索引,但可以通过这里的界面阅读:http://apps.nrbook.com/c/index.html。它也被引用为实现 PRNG 的各种源代码的参考。

    在本章讨论的算法中,上面使用的算法非常简单,也相对有效。从前一个随机数 (jran) 中获取新随机数的公式是:

    jran = (jran * ia + ic) % im;
    ran = (float) jran / (float) im;  /* normalize into the 0..1 range */
    

    其中jran 是当前随机整数。

    这个生成器在一定数量的值(“周期”)之后必然会循环自身,因此必须仔细选择常量 iaicim,以使该周期与可能的。本书提供了第 285 页的表格,其中建议了不同时期长度的常数。

    ia=1366ic=150889im=714025 是一段时间内的条目之一 229 位,比需要的多。

    最后,乘以32767 或 215-1 不是 PRNG 的一部分,而是从 0..1 伪随机浮点值产生一个正半整数。请勿更改该部分,除非扩大算法的块大小。

    【讨论】:

    • 哇,很好的反应!因此,如果我更改让我们说 ia=1300 而不是 1366 它仍然可以工作,并且由于我没有使用公开示例中使用的常量而使弄清楚它有点困难?
    • @Hawk:是的,它会起作用的。 PRNG 质量理论上会受到影响,但考虑到它的使用方式,它可能不会在函数结果中引起注意。
    • @Daniel:您在 wiki 上的实现最近被编辑过。现在似乎每次迭代交换 L 和 R 两次(实际上只是循环 l1 := l1 # f(r1)r1 永远不会改变)。我错过了什么吗?这个新版本对你有意义吗?
    • @NickBarnes:很好看。我不喜欢这种变化,因为它减少了输出的分散。现在,连续输入的结果似乎有点“组合”在一起。除了完全避免碰撞之外,最初的意图就是尽可能地避免这种情况。不过,我不认为它违反了关于碰撞的承诺。
    • @Daniel:它看起来比仅仅减少色散要差一些。由于它从不交换 L 和 R,因此只有 15 位输入被“加密”。并且三个迭代现在具有应用,反转和重新应用第一轮密码的效果......我可以看到的一个好处是它现在是一个自反转,但似乎有far better ways to do that。我已恢复编辑。
    【解决方案2】:

    这个函数看起来像一个基于 Feistel network 的块密码 - 但它缺少密钥。

    Feistel 构造是双射的,即它保证没有碰撞。有趣的部分是:r2 := l1 # f(r1)。只要f(r1) 只依赖于r1pseudo_encrypt 将是双射的,无论函数做什么。

    缺少密钥意味着任何知道源代码的人都可以恢复顺序 ID。因此,您依赖于隐匿的安全性。

    另一种方法是使用带密钥的分组密码。对于 32 位块,选择相对较少,我知道 Skip32 和 ipcrypt。对于 64 位块,有多种密码可供选择,包括 3DES、Blowfish 和 XTEA

    【讨论】:

    • 感谢您的周到回复。我知道如果有人知道源代码,他们将能够对 ID 进行逆向工程,但我担心我有办法更改此公共源代码中的一些常量,以便他们只能在他们的情况下对其进行逆向工程猜对了常数? ...例如,我可以更改此行中的任何内容以使输出不同但仍然没有冲突: r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int ;
    • @Hawk 无论您选择哪个数字,它仍然是可逆的。但是,如果您选择错误的数字,则输出将具有更强的模式。我宁愿使用我提到的算法之一,而不是调整你的函数。
    • 我完全理解它是可逆的。鉴于(1)我不太习惯在 Postgres 中构建一个 skip32 或类似功能,因为我无法通过 Google 找到一个,并且(2)如果有人真的很努力他们可以解码,我没问题,我只想稍微做一下更难,但调整了一些数字。
    • @Hawk:Postgres 在pgcrypto module 中提供 Blowfish 和 3DES 实现
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2010-10-12
    相关资源
    最近更新 更多