2015-06-07 203 views
2

我想用pseudo_encrypt功能提到在計算器上幾次,讓我的ID看起來更隨機:https://wiki.postgresql.org/wiki/Pseudo_encrypt如何自定義Postgres僞加密函數的輸出?

我怎麼可以自定義此輸出獨特的「隨機」號碼只是我。我在某處讀到,你可以改變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; 

回答

4

替代解決方案:使用不同的密碼

其他加密功能是現在的Postgres維基可用。它們將會明顯變慢,但除此之外,它們更適合用來生成自定義的隨機數字系列。

對於32位輸出,Skip32 in plpgsql將使用10字節寬的密鑰加密其輸入,因此您只需選擇自己的密鑰以擁有自己的特定排列(2^32唯一值的特定順序出來)。

對於64位輸出,XTEA in plpgsql將做類似的操作,但是使用16字節寬的密鑰。

否則,只是定製pseudo_encrypt,見下圖:約pseudo_encrypt的實施

說明:

此功能有3個屬性

  • 輸出值的全球唯一性
  • 可逆性
  • pseu做隨機效應

第一和第二財產來自於網絡的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; 

的公式和值用C來自數值食譜1366150889714025(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必須仔細選擇該期間爲儘可能地大。這本書提供了一個表格p.285,其中提供了各個時期的常量。

ia=1366ic=150889im=714025是一段比特,這比所需更多的方式中的一個條目。

最後乘以32767或2 -1不是PRNG的一部分,而是意味着從0..1個僞隨機浮點值產生一個正的半整數。除非擴大算法的塊大小,否則不要更改該部分。

+0

哇,很好的迴應!因此,如果我改變讓我們說ia = 1300而不是1366它仍然可以工作,並使其稍微難以弄清楚,因爲我沒有使用公開可用示例中使用的常量? – Hawk

+0

@霍克:是的,它會工作。 PRNG的質量會受到理論上的影響,但考慮到它的使用方式,它在功能結果中可能不太明顯。 –

+0

@Daniel:最近編輯了你在維基上的實現。它現在似乎每次迭代交換L和R *兩次(實際上循環'l1:= l1#f(r1)',而'r1'永遠不會改變)。我錯過了什麼嗎?這個新版本對你有意義嗎? –

3

這個功能貌似根據Feistel network塊密碼 - 但它缺乏一個關鍵。

Feistel結構是雙射的,即它保證沒有碰撞。有趣的部分是:r2 := l1 # f(r1)。只要f(r1)僅取決於r1pseudo_encrypt將是雙射的,無論函數做什麼。

缺少密鑰意味着任何知道源代碼的人都可以恢復順序標識。所以你依靠安全 - 雖然默默無聞。

另一種方法是使用採用密鑰的分組密碼。對於32位塊,選擇相對較少,我知道Skip32和ipcrypt。對於64位塊,有許多密碼可供選擇,包括3DES,Blowfish和XTEA

+0

感謝您的深思。我知道如果有人知道源代碼他們能夠反向設計這些ID,但是我擔心有什麼方法可以改變這些公共源代碼中的一些常量,以便他們只能對其進行反向工程正確猜測常量? ...例如,我可以改變這條線上的任何東西,所以輸出是不同的,但仍然沒有碰撞:r2:= l1#((((1366.0 * r1 + 150889)%714025)/ 714025.0)* 32767):: int ; – Hawk

+0

@Hawk無論你選擇哪個數字,它仍然是可逆的。但是如果你選擇了不好的數字,輸出將會有更強的模式。我寧願使用我提到的算法之一,而不是調整你的函數。 – CodesInChaos

+0

我完全讓你認爲它是可逆的。鑑於(1)我在Postgres中構建skip32或類似函數並不是很舒服,因爲我無法通過Google找到它,(2)如果有人真的努力嘗試解碼,我可以輕鬆做到更難但調整了一些數字。 – Hawk