Threefish cipher based raw PRN/noise generator.

This commit is contained in:
Andrey Rys 2019-03-17 17:41:21 +07:00
commit 76b80ded3a
No known key found for this signature in database
GPG Key ID: ED732729967CDBC5
11 changed files with 436 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
_*
*.swp
*.o
*.out
*.key
*.diff
*.patch
tags
libtf.a
tfrand

27
Makefile Normal file
View File

@ -0,0 +1,27 @@
PROGS = tfrand
PROGSRCS = $(PROGS:=.c)
PROGOBJS = $(PROGSRCS:.c=.o)
SRCS = $(filter-out $(PROGSRCS), $(wildcard *.c))
HDRS = $(wildcard *.h)
OBJS = $(SRCS:.c=.o)
ifneq (,$(DEBUG))
override CFLAGS+=-Wall -O0 -g
else
override CFLAGS+=-O3
endif
default: $(OBJS) libtf.a tfrand
all: $(OBJS) libtf.a $(PROGS)
%.o: %.c $(HDRS)
$(CC) $(CFLAGS) -c -o $@ $<
libtf.a: $(OBJS)
$(AR) cru $@ $^
$(PROGS): %: %.o libtf.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
clean:
rm -f libtf.a $(OBJS) $(PROGOBJS) $(SUPPOBJS) $(PROGS)

43
README Normal file
View File

@ -0,0 +1,43 @@
Threefish cipher based raw PRN/noise generator.
PURPOSE
This PRNG is shortened, 32 bit integer version of Threefish-256 block cipher.
It is technically a 128 bit block cipher with 256 bit key.
It's purpose is to generate fillers fast, for use in file or disk shredders.
It is not meant to be secure, i.e. collision/bias free, but it is good at
generating random noise equal to average output of /dev/urandom, yet much faster.
Typical performance on Athlon 5000+, x86-32 is about 170M/sec.
Included tfrand program generates random noise to stdout.
USAGE
Build example:
make tfrand
Test it:
./tfrand >rng.out
Measure performance (install tfcrypt first):
./tfrand | tfcrypt -V.5 -P - /dev/null
Use libtf.a library in your code, see headers for function references:
tfe.h: STREAM reference.
tfprng.h: PRNG reference.
WARNING
Do NOT use it as cipher! It's just a random block generator.
You have been warned.
ORIGIN
This code is derived from tfcipher library.
LICENSE
Public domain -- free to reuse and adapt.
AUTHOR
Andrey Rys <rys@lynxlynx.ru>, 17Mar2019.

50
tfcore.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef _THREEFISH_CIPHER_CORE_HEADER
#define _THREEFISH_CIPHER_CORE_HEADER
#ifndef _THREEFISH_CIPHER_DEFINITIONS_HEADER
#error Threefish definitions header is required! Include tfdef.h first.
#endif
#define ROL(x, s, max) ((x << s) | (x >> (-s & (max-1))))
#define ROR(x, s, max) ((x >> s) | (x << (-s & (max-1))))
#define KE_MIX(x, y, k1, k2, sl) \
do { \
x += k1; \
y += x; \
y += k2; \
x = ROL(x, sl, TF_UNIT_BITS); \
x ^= y; \
} while (0)
#define BE_MIX(x, y, sl) \
do { \
x += y; \
y = ROL(y, sl, TF_UNIT_BITS); \
y ^= x; \
} while (0)
#define KD_MIX(x, y, k1, k2, sr) \
do { \
x ^= y; \
x = ROR(x, sr, TF_UNIT_BITS); \
y -= x; \
y -= k2; \
x -= k1; \
} while (0)
#define BD_MIX(x, y, sr) \
do { \
y ^= x; \
y = ROR(y, sr, TF_UNIT_BITS); \
x -= y; \
} while (0)
enum tf_rotations {
TFS_KS01 = 7, TFS_KS02 = 25, TFS_KS03 = 19, TFS_KS04 = 7,
TFS_BS01 = 5, TFS_BS02 = 27, TFS_BS03 = 26, TFS_BS04 = 6,
TFS_BS05 = 14, TFS_BS06 = 11, TFS_BS07 = 24, TFS_BS08 = 18,
TFS_BS09 = 9, TFS_BS10 = 24, TFS_BS11 = 6, TFS_BS12 = 7,
};
#endif

34
tfdef.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _THREEFISH_CIPHER_DEFINITIONS_HEADER
#define _THREEFISH_CIPHER_DEFINITIONS_HEADER
#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#include <stddef.h>
#include <stdint.h>
#define TF_UNIT_TYPE uint32_t
#define TF_NR_BLOCK_BITS 128
#define TF_NR_KEY_BITS 256
#define TF_NR_BLOCK_UNITS 4
#define TF_NR_KEY_UNITS 8
#define TF_BYTE_TYPE uint8_t
#define TF_SIZE_UNIT (sizeof(TF_UNIT_TYPE))
#define TF_BLOCK_SIZE (TF_SIZE_UNIT * TF_NR_BLOCK_UNITS)
#define TF_KEY_SIZE (TF_SIZE_UNIT * TF_NR_KEY_UNITS)
#define TF_TO_BITS(x) ((x) * 8)
#define TF_FROM_BITS(x) ((x) / 8)
#define TF_MAX_BITS TF_NR_BLOCK_BITS
#define TF_UNIT_BITS (TF_SIZE_UNIT * 8)
void tf_encrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K);
#endif

57
tfe.c Normal file
View File

@ -0,0 +1,57 @@
#include <string.h>
#include "tfdef.h"
#include "tfe.h"
void tfe_init_iv(struct tfe_stream *tfe, const void *key, const void *iv)
{
memset(tfe, 0, sizeof(struct tfe_stream));
memcpy(tfe->key, key, TF_KEY_SIZE);
if (iv) memcpy(tfe->iv, iv, TF_BLOCK_SIZE);
tfe->carry_bytes = 0;
}
void tfe_init(struct tfe_stream *tfe, const void *key)
{
tfe_init_iv(tfe, key, NULL);
}
void tfe_emit(void *dst, size_t szdst, struct tfe_stream *tfe)
{
TF_BYTE_TYPE *udst = dst;
size_t sz = szdst;
if (!dst && szdst == 0) {
memset(tfe, 0, sizeof(struct tfe_stream));
return;
}
if (tfe->carry_bytes > 0) {
if (tfe->carry_bytes > szdst) {
memcpy(udst, tfe->carry_block, szdst);
memmove(tfe->carry_block, tfe->carry_block+szdst, tfe->carry_bytes-szdst);
tfe->carry_bytes -= szdst;
return;
}
memcpy(udst, tfe->carry_block, tfe->carry_bytes);
udst += tfe->carry_bytes;
sz -= tfe->carry_bytes;
tfe->carry_bytes = 0;
}
if (sz >= TF_BLOCK_SIZE) {
do {
tf_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key);
memcpy(udst, tfe->iv, TF_BLOCK_SIZE);
udst += TF_BLOCK_SIZE;
} while ((sz -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
}
if (sz) {
tf_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key);
memcpy(udst, tfe->iv, sz);
udst = (TF_BYTE_TYPE *)tfe->iv;
tfe->carry_bytes = TF_BLOCK_SIZE-sz;
memcpy(tfe->carry_block, udst+sz, tfe->carry_bytes);
}
}

17
tfe.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _TF_STREAM_CIPHER_DEFS
#define _TF_STREAM_CIPHER_DEFS
#include "tfdef.h"
struct tfe_stream {
TF_UNIT_TYPE key[TF_NR_KEY_UNITS];
TF_UNIT_TYPE iv[TF_NR_BLOCK_UNITS];
TF_BYTE_TYPE carry_block[TF_BLOCK_SIZE];
size_t carry_bytes;
};
void tfe_init(struct tfe_stream *tfe, const void *key);
void tfe_init_iv(struct tfe_stream *tfe, const void *key, const void *iv);
void tfe_emit(void *dst, size_t szdst, struct tfe_stream *tfe);
#endif

51
tfenc.c Normal file
View File

@ -0,0 +1,51 @@
#include "tfdef.h"
#include "tfcore.h"
#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6) \
do { \
KE_MIX(Y, X, k1 + k2, k3, TFS_KS01); \
KE_MIX(T, Z, k4 + x, k5 + k6, TFS_KS02); \
\
BE_MIX(X, T, TFS_BS01); BE_MIX(Z, Y, TFS_BS02); \
BE_MIX(X, Y, TFS_BS03); BE_MIX(Z, T, TFS_BS04); \
BE_MIX(X, T, TFS_BS05); BE_MIX(Z, Y, TFS_BS06); \
} while (0)
#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6) \
do { \
KE_MIX(Y, X, k1 + k2, k3, TFS_KS03); \
KE_MIX(T, Z, k4 + x, k5 + k6, TFS_KS04); \
\
BE_MIX(X, T, TFS_BS07); BE_MIX(Z, Y, TFS_BS08); \
BE_MIX(X, Y, TFS_BS09); BE_MIX(Z, T, TFS_BS10); \
BE_MIX(X, T, TFS_BS11); BE_MIX(Z, Y, TFS_BS12); \
} while (0)
void tf_encrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
{
TF_UNIT_TYPE X, Y, Z, T;
TF_UNIT_TYPE K0, K1, K2, K3;
TF_UNIT_TYPE K4, T0, T1, T2;
X = I[0]; Y = I[1]; Z = I[2]; T = I[3];
K0 = K[0]; K1 = K[1]; K2 = K[2]; K3 = K[3];
K4 = K[4]; T0 = K[5]; T1 = K[6]; T2 = K[7];
PROCESS_BLOCKP( 1,K1,T0,K0,K3,K2,T1);
PROCESS_BLOCKN( 2,K2,T1,K1,K4,K3,T2);
PROCESS_BLOCKP( 3,K3,T2,K2,K0,K4,T0);
PROCESS_BLOCKN( 4,K4,T0,K3,K1,K0,T1);
PROCESS_BLOCKP( 5,K0,T1,K4,K2,K1,T2);
PROCESS_BLOCKN( 6,K1,T2,K0,K3,K2,T0);
PROCESS_BLOCKP( 7,K2,T0,K1,K4,K3,T1);
PROCESS_BLOCKN( 8,K3,T1,K2,K0,K4,T2);
PROCESS_BLOCKP( 9,K4,T2,K3,K1,K0,T0);
PROCESS_BLOCKN(10,K0,T0,K4,K2,K1,T1);
PROCESS_BLOCKP(11,K1,T1,K0,K3,K2,T2);
PROCESS_BLOCKN(12,K2,T2,K1,K4,K3,T0);
O[0] = X + K3; O[1] = Y + K4 + T0; O[2] = Z + K0 + T1; O[3] = T + K1 + 18;
}

94
tfprng.c Normal file
View File

@ -0,0 +1,94 @@
#include <string.h>
#include "tfe.h"
#include "tfprng.h"
struct tf_prng_data {
struct tfe_stream tfe;
short init;
};
struct tf_prng_data tf_prng_sdata;
size_t tf_prng_datasize(void)
{
return sizeof(struct tf_prng_data);
}
void tf_prng_seedkey_r(void *sdata, const void *skey)
{
TF_UNIT_TYPE k[TF_NR_KEY_UNITS];
struct tf_prng_data *rprng = sdata;
memset(rprng, 0, tf_prng_datasize());
if (!skey) return;
memcpy(k, skey, TF_KEY_SIZE);
tfe_init(&rprng->tfe, k);
rprng->init = 1;
memset(k, 0, TF_KEY_SIZE);
}
void tf_prng_seedkey(const void *skey)
{
tf_prng_seedkey_r(&tf_prng_sdata, skey);
}
void tf_prng_genrandom_r(void *sdata, void *result, size_t need)
{
struct tf_prng_data *rprng = sdata;
memset(result, 0, need);
tfe_emit(result, need, &rprng->tfe);
}
void tf_prng_genrandom(void *result, size_t need)
{
tf_prng_genrandom_r(&tf_prng_sdata, result, need);
}
void tf_prng_seed_r(void *sdata, TF_UNIT_TYPE seed)
{
TF_UNIT_TYPE k[TF_NR_KEY_UNITS];
struct tf_prng_data *rprng = sdata;
size_t x;
memset(rprng, 0, tf_prng_datasize());
for (x = 0; x < TF_NR_KEY_UNITS; x++) k[x] = seed;
tfe_init(&rprng->tfe, k);
rprng->init = 1;
memset(k, 0, TF_KEY_SIZE);
}
void tf_prng_seed(TF_UNIT_TYPE seed)
{
tf_prng_seed_r(&tf_prng_sdata, seed);
}
TF_UNIT_TYPE tf_prng_random_r(void *sdata)
{
struct tf_prng_data *rprng = sdata;
TF_UNIT_TYPE r;
if (!rprng->init) return 0;
tfe_emit(&r, sizeof(r), &rprng->tfe);
return r;
}
TF_UNIT_TYPE tf_prng_random(void)
{
return tf_prng_random_r(&tf_prng_sdata);
}
TF_UNIT_TYPE tf_prng_range_r(void *sdata, TF_UNIT_TYPE s, TF_UNIT_TYPE d)
{
TF_UNIT_TYPE c = tf_prng_random_r(sdata);
if (d <= s) return s;
return s + c / ((TF_UNIT_TYPE)~0 / (d - s + 1) + 1);
}
TF_UNIT_TYPE tf_prng_range(TF_UNIT_TYPE s, TF_UNIT_TYPE d)
{
return tf_prng_range_r(&tf_prng_sdata, s, d);
}

22
tfprng.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _TF_PRNG_DEFINITIONS_HEADER
#define _TF_PRNG_DEFINITIONS_HEADER
#include <stdlib.h>
#include "tfdef.h"
#define TF_PRNG_KEY_SIZE TF_KEY_SIZE
#define TF_PRNG_SIZE_UNIT TF_SIZE_UNIT
size_t tf_prng_datasize(void);
void tf_prng_seedkey_r(void *sdata, const void *skey);
void tf_prng_seedkey(const void *skey);
void tf_prng_genrandom_r(void *sdata, void *result, size_t need);
void tf_prng_genrandom(void *result, size_t need);
void tf_prng_seed_r(void *sdata, TF_UNIT_TYPE seed);
void tf_prng_seed(TF_UNIT_TYPE seed);
TF_UNIT_TYPE tf_prng_random_r(void *sdata);
TF_UNIT_TYPE tf_prng_random(void);
TF_UNIT_TYPE tf_prng_range_r(void *sdata, TF_UNIT_TYPE s, TF_UNIT_TYPE d);
TF_UNIT_TYPE tf_prng_range(TF_UNIT_TYPE s, TF_UNIT_TYPE d);
#endif

31
tfrand.c Normal file
View File

@ -0,0 +1,31 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "tfdef.h"
#include "tfprng.h"
#define DATASIZE 65536
static char data[DATASIZE];
static char key[TF_KEY_SIZE];
int main(int argc, char **argv)
{
int fd;
fd = open("/dev/urandom", O_RDONLY);
if (fd != -1) {
read(fd, key, sizeof(key));
close(fd);
}
tf_prng_seedkey(key);
while (1) {
tf_prng_genrandom(data, DATASIZE);
if (write(1, data, DATASIZE) == -1) return 1;
}
tf_prng_seedkey(NULL);
return 0;
}