伪加密
来自 PostgreSQL 维基
跳转到导航跳转到搜索
pseudo_encrypt(int) 可用作唯一值的伪随机生成器。它产生一个整数输出,该输出与其整数输入(通过数学排列)唯一关联,但同时看起来是随机的,且无碰撞。这对于在不透露序列中序数位置的情况下(对于票号、URL 短码、促销代码等)通信按顺序生成的数字非常有用。
排列属性是该函数是 Feistel 网络的结果;参见http://en.wikipedia.org/wiki/Feistel_cipher
它执行非常简单的加密,没有密钥(在某种程度上,密钥在算法中被硬编码)。
- 要使用密钥加密 32 位值,请参见Skip32(仍在 plpgsql 中)。
- 要使用密钥加密 64 位值,请参见XTEA
- 要将输出限制为更小的任意范围,例如具有 N 个小数位的数字,请参见Pseudo_encrypt_constrained_to_an_arbitrary_range
此代码的第一个版本发布在http://archives.postgresql.org/pgsql-general/2009-05/msg00082.php 中,由 Daniel Vérité 撰写;下面是一个改进版本,遵循 Jaka Jancar 的评论。
CREATE OR REPLACE FUNCTION pseudo_encrypt(value int) returns int AS $$
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 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;
l1 := l2;
r1 := r2;
i := i + 1;
END LOOP;
return ((r1 << 16) + l1);
END;
$$ LANGUAGE plpgsql strict immutable;
注释
- 它返回一个带符号的整数(无论如何,postgres 没有无符号整数)。
- 它是自逆的,也就是说:pseudo_encrypt(pseudo_encrypt(X)) = X
- 输出可以通过更改 r1 的此函数进行自定义
((1366 * r1 + 150889) % 714025) / 714025.0)(受随机生成器启发),使用您自己的“秘密配方”。替换必须是数学意义上的函数(即,如果x=y,则f(x)=f(y)),并生成 0 到 1 之间的值。
示例输出
select x,pseudo_encrypt(x) from generate_series(-10,10) as x; x | pseudo_encrypt -----+---------------- -10 | -1270576520 -9 | -236348969 -8 | -1184061109 -7 | -25446276 -6 | -1507538963 -5 | -518858927 -4 | -1458116927 -3 | -532482573 -2 | -157973154 -1 | -1105881908 0 | 1777613459 1 | 561465857 2 | 436885871 3 | 576481439 4 | 483424269 5 | 1905133426 6 | 971249312 7 | 1926833684 8 | 735327624 9 | 1731020007 10 | 792482838
C 版本
这是一个在 C 中实现的等效函数
#include "postgres.h"
#include "fmgr.h"
#include <math.h>
PG_FUNCTION_INFO_V1(simple_feistel_self_inverse);
Datum
simple_feistel_self_inverse(PG_FUNCTION_ARGS)
{
int32 val = PG_GETARG_INT32(0);
int32 l1 = (val >> 16) & 0xffff;
int32 r1 = val & 0xffff;
int32 l2, r2;
int i;
for (i = 0; i < 3; i++)
{
l2 = r1;
/* round() is used to produce the same values as the
plpgsql implementation that does an SQL cast to INT */
r2 = l1 ^ (int32)round((((1366*r1 + 150889) % 714025) / 714025.0) * 32767);
l1 = l2;
r1 = r2;
}
PG_RETURN_INT32((r1 << 16) + l1);
}
使用 SQL 创建
CREATE OR REPLACE FUNCTION simple_feistel_self_inverse(int4)
RETURNS int4
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;