commit 76b80ded3a68707773e3dc7d5888bcd669ea248f Author: Andrey Rys Date: Sun Mar 17 17:41:21 2019 +0700 Threefish cipher based raw PRN/noise generator. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c26d2c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +_* +*.swp +*.o +*.out +*.key +*.diff +*.patch +tags +libtf.a +tfrand diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d4b613c --- /dev/null +++ b/Makefile @@ -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) diff --git a/README b/README new file mode 100644 index 0000000..63f1e7c --- /dev/null +++ b/README @@ -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 , 17Mar2019. diff --git a/tfcore.h b/tfcore.h new file mode 100644 index 0000000..f2dd59a --- /dev/null +++ b/tfcore.h @@ -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 diff --git a/tfdef.h b/tfdef.h new file mode 100644 index 0000000..38b354c --- /dev/null +++ b/tfdef.h @@ -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 +#include + +#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 diff --git a/tfe.c b/tfe.c new file mode 100644 index 0000000..8c58979 --- /dev/null +++ b/tfe.c @@ -0,0 +1,57 @@ +#include +#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); + } +} diff --git a/tfe.h b/tfe.h new file mode 100644 index 0000000..f5793b1 --- /dev/null +++ b/tfe.h @@ -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 diff --git a/tfenc.c b/tfenc.c new file mode 100644 index 0000000..d0727dc --- /dev/null +++ b/tfenc.c @@ -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; +} diff --git a/tfprng.c b/tfprng.c new file mode 100644 index 0000000..d4370f3 --- /dev/null +++ b/tfprng.c @@ -0,0 +1,94 @@ +#include +#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); +} diff --git a/tfprng.h b/tfprng.h new file mode 100644 index 0000000..5fbab0a --- /dev/null +++ b/tfprng.h @@ -0,0 +1,22 @@ +#ifndef _TF_PRNG_DEFINITIONS_HEADER +#define _TF_PRNG_DEFINITIONS_HEADER + +#include +#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 diff --git a/tfrand.c b/tfrand.c new file mode 100644 index 0000000..cbbe82a --- /dev/null +++ b/tfrand.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#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; +}