伪加密

来自 PostgreSQL 维基
跳转到导航跳转到搜索

库代码片段

pseudo_encrypt

与 PostgreSQL 兼容

任何版本

PL/pgSQL

依赖于


pseudo_encrypt(int) 可用作唯一值的伪随机生成器。它产生一个整数输出,该输出与其整数输入(通过数学排列)唯一关联,但同时看起来是随机的,且无碰撞。这对于在不透露序列中序数位置的情况下(对于票号、URL 短码、促销代码等)通信按顺序生成的数字非常有用。

排列属性是该函数是 Feistel 网络的结果;参见http://en.wikipedia.org/wiki/Feistel_cipher

它执行非常简单的加密,没有密钥(在某种程度上,密钥在算法中被硬编码)。


此代码的第一个版本发布在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;

另请参见