Skip to content

Commit f72c8e9

Browse files
committed
Initial commit
0 parents  commit f72c8e9

File tree

10 files changed

+1155
-0
lines changed

10 files changed

+1155
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/*.dSYM/
2+
/results/
3+
/pgspeck.so
4+
*.swp
5+
/*.o

Makefile

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
MODULE_big = pgspeck
2+
OBJS = speck.o pgspeck.o
3+
4+
EXTENSION = pgspeck
5+
DATA = pgspeck--1.0.sql
6+
7+
REGRESS = pgspeck
8+
9+
ifdef NO_PGXS
10+
subdir = contrib/pgspeck
11+
top_builddir = ../..
12+
include $(top_builddir)/src/Makefile.global
13+
include $(top_srcdir)/contrib/contrib-global.mk
14+
else
15+
PG_CONFIG = pg_config
16+
PGXS := $(shell $(PG_CONFIG) --pgxs)
17+
include $(PGXS)
18+
endif

README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
pgspeck is a PostgreSQL extension for symmetrical encryption using the
2+
[Speck](https://en.wikipedia.org/wiki/Speck_(cipher)) encryption algorithms.
3+
Only 32-bit and 48-bit block sizes, with 64-bit and 96-bit keys (respectively)
4+
are supported. The primary use case is generating a random-looking sequence
5+
from an increasing sequence.
6+
7+
The extension adds four functions:
8+
9+
-- Encrypts a 32-bit plaintext using a 64-bit key. Only the lowest 32 bits
10+
-- from the plaintext are used; the key's full 64-bit range is used.
11+
CREATE FUNCTION pgspeck_encrypt32(plaintext int8, key int8)
12+
RETURNS int8
13+
AS 'pgspeck', 'pgspeck_encrypt32' LANGUAGE c STRICT;
14+
15+
-- Decrypts a value encrypted with pgspeck_encrypt32.
16+
CREATE FUNCTION pgspeck_decrypt32(ciphertext int8, key int8)
17+
RETURNS int8
18+
AS 'pgspeck', 'pgspeck_decrypt32' LANGUAGE c STRICT;
19+
20+
-- Encrypts a 48-bit plaintext using a 96-bit key. Only the lowest 48 bits
21+
-- from each argument are used.
22+
CREATE FUNCTION pgspeck_encrypt48(plaintext int8, key1 int8, key2 int8)
23+
RETURNS int8
24+
AS 'pgspeck', 'pgspeck_encrypt48' LANGUAGE c STRICT;
25+
26+
-- Decrypts a value encrypted with pgspeck_encrypt48.
27+
CREATE FUNCTION pgspeck_decrypt48(ciphertext int8, key1 int8, key2 int8)
28+
RETURNS int8
29+
AS 'pgspeck', 'pgspeck_decrypt48' LANGUAGE c STRICT;

expected/pgspeck.out

+825
Large diffs are not rendered by default.

pgspeck--1.0.sql

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
2+
\echo Use "CREATE EXTENSION pgspeck" to load this file. \quit
3+
4+
CREATE FUNCTION pgspeck_encrypt32(plaintext int8, key int8)
5+
RETURNS int8
6+
AS 'pgspeck', 'pgspeck_encrypt32' LANGUAGE c STRICT;
7+
8+
CREATE FUNCTION pgspeck_decrypt32(ciphertext int8, key int8)
9+
RETURNS int8
10+
AS 'pgspeck', 'pgspeck_decrypt32' LANGUAGE c STRICT;
11+
12+
CREATE FUNCTION pgspeck_encrypt48(plaintext int8, key1 int8, key2 int8)
13+
RETURNS int8
14+
AS 'pgspeck', 'pgspeck_encrypt48' LANGUAGE c STRICT;
15+
16+
CREATE FUNCTION pgspeck_decrypt48(ciphertext int8, key1 int8, key2 int8)
17+
RETURNS int8
18+
AS 'pgspeck', 'pgspeck_decrypt48' LANGUAGE c STRICT;
19+

pgspeck.c

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "pgspeck.h"
2+
#include "postgres.h"
3+
#include "funcapi.h"
4+
#include "fmgr.h"
5+
6+
7+
PG_MODULE_MAGIC;
8+
9+
Datum pgspeck_encrypt32(PG_FUNCTION_ARGS);
10+
PG_FUNCTION_INFO_V1(pgspeck_encrypt32);
11+
12+
Datum
13+
pgspeck_encrypt32(PG_FUNCTION_ARGS)
14+
{
15+
int64 plaintext = PG_GETARG_INT64(0);
16+
int64 key = PG_GETARG_INT64(1);
17+
18+
PG_RETURN_INT64(speck_encrypt32((uint32) plaintext, key));
19+
}
20+
21+
Datum pgspeck_decrypt32(PG_FUNCTION_ARGS);
22+
PG_FUNCTION_INFO_V1(pgspeck_decrypt32);
23+
24+
Datum
25+
pgspeck_decrypt32(PG_FUNCTION_ARGS)
26+
{
27+
int64 ciphertext = PG_GETARG_INT64(0);
28+
int64 key = PG_GETARG_INT64(1);
29+
30+
PG_RETURN_INT64(speck_decrypt32((uint32) ciphertext, key));
31+
}
32+
33+
34+
Datum pgspeck_encrypt48(PG_FUNCTION_ARGS);
35+
PG_FUNCTION_INFO_V1(pgspeck_encrypt48);
36+
37+
Datum
38+
pgspeck_encrypt48(PG_FUNCTION_ARGS)
39+
{
40+
int64 plaintext = PG_GETARG_INT64(0);
41+
int64 key1 = PG_GETARG_INT64(1);
42+
int64 key2 = PG_GETARG_INT64(2);
43+
const int64 keys[2] = { key1, key2 };
44+
45+
PG_RETURN_INT64(speck_encrypt48(plaintext, keys));
46+
}
47+
48+
Datum pgspeck_decrypt48(PG_FUNCTION_ARGS);
49+
PG_FUNCTION_INFO_V1(pgspeck_decrypt48);
50+
51+
Datum
52+
pgspeck_decrypt48(PG_FUNCTION_ARGS)
53+
{
54+
int64 ciphertext = PG_GETARG_INT64(0);
55+
int64 key1 = PG_GETARG_INT64(1);
56+
int64 key2 = PG_GETARG_INT64(2);
57+
const int64 keys[2] = { key1, key2 };
58+
59+
PG_RETURN_INT64(speck_decrypt48(ciphertext, keys));
60+
}

pgspeck.control

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
comment = 'pgspeck'
2+
default_version = '1.0'
3+
4+
relocatable = true

pgspeck.h

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef __PG_SPECK_SPECK_HEADER__
2+
#define __PG_SPECK_SPECK_HEADER__
3+
4+
#include "postgres.h"
5+
6+
uint32 speck_encrypt32(const uint32 xy, const int64 K);
7+
uint32 speck_decrypt32(const uint32 xy, const int64 K);
8+
int64 speck_encrypt48(const int64 xy, const int64 *K);
9+
int64 speck_decrypt48(const int64 xy, const int64 *K);
10+
11+
#endif

speck.c

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "pgspeck.h"
2+
3+
4+
#define _CIRCULAR_SHIFT(val, n, wordsize, op1, op2) (((val) op1 (n)) | ((val) op2 ((wordsize) - (n))))
5+
6+
#define ROL16(val, n) _CIRCULAR_SHIFT(val, n, 16, <<, >>)
7+
#define ROR16(val, n) _CIRCULAR_SHIFT(val, n, 16, >>, <<)
8+
9+
#define ROL24(val, n) (_CIRCULAR_SHIFT(val, n, 24, <<, >>) & 0xFFFFFF)
10+
#define ROR24(val, n) (_CIRCULAR_SHIFT(val, n, 24, >>, <<) & 0xFFFFFF)
11+
12+
13+
static void speck_key_expand32(const int64 K, uint16 *k);
14+
static void speck_key_expand48(const int64 *K, uint32 *k);
15+
16+
17+
static void
18+
speck_key_expand32(const int64 K, uint16 *k)
19+
{
20+
uint16 l[22];
21+
int i;
22+
23+
l[2] = (K & 0xFFFF000000000000) >> 48;
24+
l[1] = (K & 0x0000FFFF00000000) >> 32;
25+
l[0] = (K & 0x00000000FFFF0000) >> 16;
26+
27+
for (i = 0; i < 22-1; ++i)
28+
{
29+
l[i+3] = ((uint16) (k[i] + ROR16(l[i], 7))) ^ i;
30+
k[i+1] = (ROL16(k[i], 2) ^ l[i+3]);
31+
}
32+
}
33+
34+
uint32
35+
speck_encrypt32(const uint32 xy, const int64 K)
36+
{
37+
uint32 i;
38+
uint16 k[22];
39+
40+
k[0] = (K & 0xFFFF);
41+
speck_key_expand32(K, k);
42+
43+
uint16 x = (xy & 0xFFFF0000) >> 16, y = (xy & 0xFFFF);
44+
for (i = 0; i < 22; i++)
45+
{
46+
x = (uint16) (ROR16(x, 7) + y);
47+
x ^= k[i];
48+
y = ROL16(y, 2) ^ x;
49+
}
50+
return (x << 16) | y;
51+
}
52+
53+
uint32
54+
speck_decrypt32(const uint32 xy, const int64 K)
55+
{
56+
signed int i;
57+
uint16 k[22];
58+
59+
k[0] = (K & 0xFFFF);
60+
speck_key_expand32(K, k);
61+
62+
uint16 x = (xy & 0xFFFF0000) >> 16, y = (xy & 0xFFFF);
63+
for (i = 21; i >= 0; i--)
64+
{
65+
y = ROR16(x ^ y, 2);
66+
x = (uint16) ((x ^ k[i]) - y);
67+
x = ROL16(x, 7);
68+
}
69+
return (x << 16) | y;
70+
}
71+
72+
static void
73+
speck_key_expand48(const int64 *K, uint32 *k)
74+
{
75+
int i;
76+
uint32 l[23];
77+
78+
l[2] = (K[0] & 0xFFFFFF000000) >> 24;
79+
l[1] = (K[0] & 0x000000FFFFFF) >> 0;
80+
l[0] = (K[1] & 0xFFFFFF000000) >> 24;
81+
82+
for (i = 0; i < 23-1; ++i)
83+
{
84+
l[i+3] = ((k[i] + ROR24(l[i], 8)) & 0xFFFFFF) ^ i;
85+
k[i+1] = (ROL24(k[i], 3) ^ l[i+3]);
86+
}
87+
}
88+
89+
int64
90+
speck_encrypt48(const int64 xy, const int64 *K)
91+
{
92+
int i;
93+
uint32 k[23];
94+
95+
k[0] = (K[1] & 0xFFFFFF);
96+
speck_key_expand48(K, k);
97+
98+
uint32 x = (xy & 0xFFFFFF000000) >> 24, y = (xy & 0xFFFFFF);
99+
for (i = 0; i < 23; i++)
100+
{
101+
x = ((ROR24(x, 8) + y) & 0xFFFFFF);
102+
x ^= k[i];
103+
y = ROL24(y, 3) ^ x;
104+
}
105+
return (((int64) x) << 24) | (int64) y;
106+
}
107+
108+
int64
109+
speck_decrypt48(const int64 xy, const int64 *K)
110+
{
111+
signed int i;
112+
uint32 k[23];
113+
114+
k[0] = (K[1] & 0xFFFFFF);
115+
speck_key_expand48(K, k);
116+
117+
uint32 x = (xy & 0xFFFFFF000000) >> 24, y = (xy & 0xFFFFFF);
118+
for (i = 22; i >= 0; i--)
119+
{
120+
y = ROR24(x ^ y, 3);
121+
x = (((x ^ k[i]) - y) & 0xFFFFFF);
122+
x = ROL24(x, 8);
123+
}
124+
return (((int64) x) << 24) | (int64) y;
125+
}

sql/pgspeck.sql

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
CREATE EXTENSION pgspeck;
2+
3+
-- test vector from the original whitepaper
4+
select to_hex(pgspeck_encrypt32((x'6574694c')::int8, (x'1918111009080100')::int8));
5+
6+
select u.val, k.key, pgspeck_decrypt32(pgspeck_encrypt32(u.val, k.key), k.key)
7+
from
8+
unnest(array[
9+
-- edge values
10+
0, 1, 4294967294, 4294967295,
11+
12+
-- a randomly generated set of values
13+
340411100,3648991854,3883173854,2911300352,170217392,3281780748,2743510608,2227816056,4223735584,1560485918,
14+
3927159578,3284820474,1333891060,598245358,2408391506,2297414002,2228884466,1475149318,990315928,1065154076,
15+
4010714368,60823918,2570889252,816192832,3693574190,4127177550,2057598664,941954836,3111942606,3694457644,
16+
3392854510,4199690084,1837942636,3844069376,3854292914,70869752,3595719730,2272830742,1110902212,1059850778,
17+
3495696238,743094494,49703956,534620002,1341339854,2458095464,2832034006,3570224320,3933244782,382234993
18+
]) u(val)
19+
cross join (values
20+
(int8 '0'),
21+
('1'),
22+
('7371941163172890000'),
23+
('1589783502606012418'),
24+
('9223372036854775807'),
25+
('-9223372036854775808')
26+
) k(key);
27+
28+
29+
-- test vector from the original whitepaper
30+
31+
select to_hex(pgspeck_encrypt48((x'6d2073696874')::int8, (x'1a1918121110')::int8, (x'0a0908020100')::int8));
32+
33+
select
34+
u.val,
35+
k.key1,
36+
k.key2,
37+
pgspeck_encrypt48(u.val, k.key1, k.key2) as encrypted,
38+
pgspeck_decrypt48(pgspeck_encrypt48(u.val, k.key1, k.key2), k.key1, k.key2) as decrypted
39+
from unnest(array[
40+
-- edge values
41+
0, 1, 281474976710654, 281474976710655,
42+
43+
-- a randomly generated set of values
44+
340411100,3648991854,3883173854,2911300352,170217392,3281780748,2743510608,2227816056,4223735584,1560485918,
45+
3927159578,3284820474,1333891060,598245358,2408391506,2297414002,2228884466,1475149318,990315928,1065154076,
46+
4010714368,60823918,2570889252,816192832,3693574190,4127177550,2057598664,941954836,3111942606,3694457644,
47+
3392854510,4199690084,1837942636,3844069376,3854292914,70869752,3595719730,2272830742,1110902212,1059850778,
48+
3495696238,743094494,49703956,534620002,1341339854,2458095464,2832034006,3570224320,3933244782,382234993
49+
]) u(val)
50+
cross join (values
51+
(int8 '0', int8 '0'),
52+
('0', '1'),
53+
('1', '0'),
54+
('737194116','3172890000'),
55+
('158978350','2606012418'),
56+
('922337203','6854775807'),
57+
('281474976710655','281474976710655'),
58+
('-281474976710656','-281474976710656')
59+
) k(key1, key2);

0 commit comments

Comments
 (0)