more modifications

This commit is contained in:
git@daemon.de
2015-10-02 17:52:29 +02:00
parent 761544a28d
commit 47f0ff9e9c
3 changed files with 132 additions and 62 deletions

View File

@@ -1,7 +1,8 @@
LDFLAGS = -g
CFLAGS = -g -Wall -Wextra -Werror
LDFLAGS = -g -O3
CFLAGS = -g -O3 -Wall -Wextra -Werror
DST = twenty4
OBJS = twenty4.o
K = 123456trewqasdfgbvcx
all: $(DST)
cd analyze && make
@@ -14,6 +15,30 @@ $(DST): $(OBJS)
gcc -c $(CFLAGS) $*.c -o $*.o
clean:
rm -f *.o $(DST)
rm -f *.o $(DST) *.core
cd analyze && make clean
cd sbox && make clean
test:
sha256 LICENSE | cut -f 4 -d ' ' > .xsum
cat LICENSE | ./$(DST) $(K) X > .xenc
cat .xenc | ./$(DST) $(K) X > .xdec
sha256 .xdec | cut -f 4 -d ' ' > .xnsum
if test "x`cat .xsum`" = "x`cat .xnsum`"; then echo OK; else echo FAIL; fi
rm -f .x*
./divtest.sh
rngtest:
@dd if=/dev/zero of=zero bs=1024 count=10000
@cat zero | ./twenty4 00000000000000000001 1 > x
# my own
analyze/analyze x
@echo
# ent from: http://www.fourmilab.ch/random/
ent x
@echo
# dieharder from: https://www.phy.duke.edu/~rgb/General/dieharder.php
dd if=/dev/zero of=/dev/stdout | ./twenty4 00000000000000000001 1 | dieharder -g 200 -a

View File

@@ -4,9 +4,11 @@
This is the implementation of the fun stream cipher TWENTY4/160 by T.v. Dein, 09/2015.
Published under the public domain, Creative Commons Zero License. It works bytewise,
uses a 160 bit key bits in 8 rounds, applies an S-Box. From the key various PRNGs
are seeded, all those PRNGs are recombined into an output key stream, which is being
xored with the input (after applying of the sbox).
uses a 160 bit key in 8 rounds including an S-Box. A random nonce is added for more
security as IV, each output byte is used as the next IV (like CBC mode). From the key
various PRNGs are seeded, all those PRNGs are recombined into an output key stream,
which is being xored with the IV and then applied to the sbox; the result is then xored
with the input..
The name TWENTY4 is a reference to article 20 paragraph 4 of the german constitution
which reads:
@@ -44,15 +46,13 @@ checksum: 29bfd8bd6dbca696d4d8b7ca997497e091875d6bf939e9702b1edf669d0742b0.
However, it just prints out bytes which it reads from STDIN, collecting them into an 256
byte array, ignoring possible duplicates, and prints it out as hex.
Both S-Boxes are bijective and have the following properties (calculated using analyze.c):
The S-Box is bijective and has the following properties (calculated using analyze.c):
Char distribution: 100.000000%
Char redundancy: 0.000000%
Char entropy: 8.000000 bits/char
Compression rate: 0.000000%
TWENTY4 uses two S-Box arrays, one for key expansion and one for encryption.
## Key expansion
FIXME.
@@ -76,11 +76,11 @@ passphrase.
My own measurement, see analyze.c:
File size: 35147 bytes
Char distribution: 100.000000%
Char redundancy: 0.000000%
Char entropy: 7.994904 bits/char
Compression rate: 0.000000% (35147 => 35168 bytes)
File size: 10240000 bytes
Char distribution: 99.609375%
Char redundancy: 0.390625%
Char entropy: 7.999984 bits/char
Compression rate: 0.000000% (10240000 => 10243131 bytes)
For comparision, AES result:
@@ -94,29 +94,19 @@ For comparision, AES result:
(ent from http://www.fourmilab.ch/random/):
Entropy = 7.995333 bits per byte.
Optimum compression would reduce the size
of this 35147 byte file by 0 percent.
Chi square distribution for 35147 samples is 229.98, and randomly
would exceed this value 86.79 percent of the times.
Arithmetic mean value of data bytes is 127.6631 (127.5 = random).
Monte Carlo value for Pi is 3.172955438 (error 1.00 percent).
Serial correlation coefficient is -0.004405 (totally uncorrelated = 0.0).
Entropy = 7.999984 bits per byte.
Optimum compression would reduce the size
of this 10240000 byte file by 0 percent.
Chi square distribution for 10240000 samples is 221.67, and randomly
would exceed this value 93.52 percent of the times.
Arithmetic mean value of data bytes is 127.4901 (127.5 = random).
Monte Carlo value for Pi is 3.142712165 (error 0.04 percent).
Serial correlation coefficient is -0.000012 (totally uncorrelated = 0.0).
Entropy = 7.994904 bits per byte.
Optimum compression would reduce the size
of this 35147 byte file by 0 percent.
Chi square distribution for 35147 samples is 248.29, and randomly
would exceed this value 60.64 percent of the times.
Arithmetic mean value of data bytes is 127.9724 (127.5 = random).
Monte Carlo value for Pi is 3.101929315 (error 1.26 percent).
Serial correlation coefficient is -0.000624 (totally uncorrelated = 0.0).
For comparision, AES result:
@@ -140,6 +130,28 @@ I ran the cipher against the dieharder test suite this way:
Find the results in analyze/dieharder160.log
## Output test
- same clear text slightly different key
IN: 111111111111, KEY: 00000000000000000001, NONCE: 1, OUT: 8201 cedd ec74 f55b f6a8 a7eb
IN: 111111111111, KEY: 00000000000000000002, NONCE: 2, OUT: 964d 0939 cf94 a158 a259 ff4e
IN: 111111111111, KEY: 00000000000000000003, NONCE: 3, OUT: db9a 4e08 9ac8 3297 6457 b8aa
IN: 111111111111, KEY: 00000000000000000004, NONCE: 4, OUT: 4946 2ce3 fd4a f4e8 95aa 985a
IN: 111111111111, KEY: 00000000000000000005, NONCE: 5, OUT: 5f5f 4eaf c0d2 4363 9b18 2eb4
IN: 111111111111, KEY: 00000000000000000006, NONCE: 6, OUT: e8df deb7 2afe 3783 98d6 8c3f
IN: 111111111111, KEY: 00000000000000000007, NONCE: 7, OUT: 6e3a 27d5 06ed eeca ad3b e7c0
IN: 111111111111, KEY: 00000000000000000008, NONCE: 8, OUT: 1c31 4f9b 58d4 1cbd c0cd 0885
- same key, slightly different clear text
IN: 111111111111, KEY: 00000000000000000001, NONCE: 1, OUT: 8201 cedd ec74 f55b f6a8 a7eb
IN: 111111111112, KEY: 00000000000000000001, NONCE: 2, OUT: 031c 6a54 b299 dcc1 5726 57e4
IN: 111111111113, KEY: 00000000000000000001, NONCE: 3, OUT: cd12 a615 1ce0 6b95 3ca8 d4b7
IN: 111111111114, KEY: 00000000000000000001, NONCE: 4, OUT: 4a6e a49f e68b 4fe7 61ac 4642
IN: 111111111115, KEY: 00000000000000000001, NONCE: 5, OUT: 999f 44a0 f563 1c06 64d1 e710
IN: 111111111116, KEY: 00000000000000000001, NONCE: 6, OUT: 92d0 e5e0 67c4 0076 c3d7 4130
IN: 111111111117, KEY: 00000000000000000001, NONCE: 7, OUT: f6c2 59fd bdd0 2298 9975 3757
IN: 111111111118, KEY: 00000000000000000001, NONCE: 8, OUT: 830b 63d4 15f9 fb41 3cd3 0c62
So, all those checks don't look that bad, but of course this doesn't
say much about TWENTY4/160's security. However, not THAT bad for the first cipher :)

View File

@@ -27,26 +27,27 @@ typedef struct _ctx ctx;
ctx *context;
/* sbox used for i/o stream diffusion */
const uint8_t sbox[] = {
0x61, 0x2d, 0x19, 0xf3, 0xe5, 0xd9, 0xde, 0x5f, 0x41, 0x31, 0xa7, 0xc2, 0x48, 0x02, 0xef, 0x98,
0x67, 0xcb, 0x6e, 0x4c, 0xf4, 0x11, 0xfa, 0x87, 0x0f, 0x6f, 0x0a, 0x3b, 0x71, 0x09, 0x1a, 0xb8,
0x3c, 0x44, 0xd8, 0xd4, 0xc8, 0x91, 0x6d, 0x8c, 0x2f, 0xce, 0x85, 0x22, 0xd5, 0x08, 0xa6, 0x97,
0x68, 0xbc, 0x3a, 0xa0, 0xbf, 0xa5, 0x47, 0x94, 0x83, 0xd1, 0x18, 0x29, 0x03, 0xb2, 0xa4, 0xfe,
0xe4, 0x4d, 0xdf, 0x21, 0xc0, 0x70, 0x4f, 0x90, 0x04, 0x40, 0x0b, 0x49, 0xe0, 0x25, 0xd7, 0xda,
0xf8, 0x1f, 0x9e, 0x76, 0xbb, 0xaa, 0xc5, 0x2e, 0x72, 0x64, 0xd6, 0x74, 0x10, 0x78, 0xfd, 0x45,
0x80, 0x4e, 0x7f, 0x12, 0xb7, 0xc6, 0xea, 0xb3, 0x37, 0x5a, 0xf2, 0xc3, 0xb6, 0x5b, 0x81, 0x95,
0xbd, 0xb0, 0xae, 0x8f, 0xd2, 0xcf, 0x1e, 0xc7, 0xee, 0xa1, 0x7a, 0xb9, 0x06, 0xa8, 0xb1, 0x93,
0x30, 0xad, 0x33, 0x77, 0x3d, 0x7c, 0xb4, 0x36, 0x92, 0x15, 0x89, 0x7e, 0xe9, 0x17, 0x07, 0x8a,
0x9f, 0x32, 0x2c, 0xf9, 0xb5, 0x7d, 0xeb, 0x23, 0xdc, 0x2b, 0x63, 0x88, 0x56, 0x42, 0x84, 0x4b,
0x0e, 0xec, 0x8d, 0x7b, 0x05, 0xed, 0xca, 0xe8, 0xe6, 0xba, 0x01, 0x5d, 0x26, 0x28, 0x13, 0x9d,
0x54, 0x59, 0xfb, 0xf0, 0xd3, 0xf7, 0xdb, 0xe7, 0xbe, 0x58, 0x5e, 0x99, 0x65, 0x8b, 0x20, 0xa3,
0xc1, 0x1c, 0xaf, 0xac, 0x55, 0xe3, 0xdd, 0x62, 0x2a, 0xcc, 0xd0, 0xe2, 0x0c, 0x66, 0x96, 0x8e,
0xab, 0xfc, 0xc4, 0x1d, 0x6a, 0x6c, 0x3f, 0x9b, 0x9a, 0x51, 0xa2, 0x86, 0x52, 0x4a, 0x43, 0x14,
0x75, 0xff, 0xf5, 0xcd, 0x1b, 0x0d, 0x35, 0x24, 0x9c, 0xe1, 0x60, 0x73, 0x3e, 0x39, 0x53, 0x16,
0x50, 0x6b, 0xc9, 0x46, 0x57, 0x5c, 0x69, 0x79, 0x82, 0xf1, 0x27, 0x38, 0x34, 0xf6, 0x00, 0xa9,
const uint8_t sbox[16][16] = {
{ 0x61, 0x2d, 0x19, 0xf3, 0xe5, 0xd9, 0xde, 0x5f, 0x41, 0x31, 0xa7, 0xc2, 0x48, 0x02, 0xef, 0x98 },
{ 0x67, 0xcb, 0x6e, 0x4c, 0xf4, 0x11, 0xfa, 0x87, 0x0f, 0x6f, 0x0a, 0x3b, 0x71, 0x09, 0x1a, 0xb8 },
{ 0x3c, 0x44, 0xd8, 0xd4, 0xc8, 0x91, 0x6d, 0x8c, 0x2f, 0xce, 0x85, 0x22, 0xd5, 0x08, 0xa6, 0x97 },
{ 0x68, 0xbc, 0x3a, 0xa0, 0xbf, 0xa5, 0x47, 0x94, 0x83, 0xd1, 0x18, 0x29, 0x03, 0xb2, 0xa4, 0xfe },
{ 0xe4, 0x4d, 0xdf, 0x21, 0xc0, 0x70, 0x4f, 0x90, 0x04, 0x40, 0x0b, 0x49, 0xe0, 0x25, 0xd7, 0xda },
{ 0xf8, 0x1f, 0x9e, 0x76, 0xbb, 0xaa, 0xc5, 0x2e, 0x72, 0x64, 0xd6, 0x74, 0x10, 0x78, 0xfd, 0x45 },
{ 0x80, 0x4e, 0x7f, 0x12, 0xb7, 0xc6, 0xea, 0xb3, 0x37, 0x5a, 0xf2, 0xc3, 0xb6, 0x5b, 0x81, 0x95 },
{ 0xbd, 0xb0, 0xae, 0x8f, 0xd2, 0xcf, 0x1e, 0xc7, 0xee, 0xa1, 0x7a, 0xb9, 0x06, 0xa8, 0xb1, 0x93 },
{ 0x30, 0xad, 0x33, 0x77, 0x3d, 0x7c, 0xb4, 0x36, 0x92, 0x15, 0x89, 0x7e, 0xe9, 0x17, 0x07, 0x8a },
{ 0x9f, 0x32, 0x2c, 0xf9, 0xb5, 0x7d, 0xeb, 0x23, 0xdc, 0x2b, 0x63, 0x88, 0x56, 0x42, 0x84, 0x4b },
{ 0x0e, 0xec, 0x8d, 0x7b, 0x05, 0xed, 0xca, 0xe8, 0xe6, 0xba, 0x01, 0x5d, 0x26, 0x28, 0x13, 0x9d },
{ 0x54, 0x59, 0xfb, 0xf0, 0xd3, 0xf7, 0xdb, 0xe7, 0xbe, 0x58, 0x5e, 0x99, 0x65, 0x8b, 0x20, 0xa3 },
{ 0xc1, 0x1c, 0xaf, 0xac, 0x55, 0xe3, 0xdd, 0x62, 0x2a, 0xcc, 0xd0, 0xe2, 0x0c, 0x66, 0x96, 0x8e },
{ 0xab, 0xfc, 0xc4, 0x1d, 0x6a, 0x6c, 0x3f, 0x9b, 0x9a, 0x51, 0xa2, 0x86, 0x52, 0x4a, 0x43, 0x14 },
{ 0x75, 0xff, 0xf5, 0xcd, 0x1b, 0x0d, 0x35, 0x24, 0x9c, 0xe1, 0x60, 0x73, 0x3e, 0x39, 0x53, 0x16 },
{ 0x50, 0x6b, 0xc9, 0x46, 0x57, 0x5c, 0x69, 0x79, 0x82, 0xf1, 0x27, 0x38, 0x34, 0xf6, 0x00, 0xa9 }
};
/* convert a 64bit number into an 8 element byte array */
void w2a(u64 in, uint8_t *out) {
out[0] = (in >> 56) & 0xFF;
@@ -59,6 +60,22 @@ void w2a(u64 in, uint8_t *out) {
out[7] = in & 0xFF;
}
/* apply sbox.
X axis = middle 4 bits
Y axis = outer bits (2 left, 2 right) */
byte apply_sbox(byte in) {
byte x, y;
/* middle 4 */
x = (in & 60) >> 2;
/* left 2 added with right 2 */
y = ((in & 192) >> 4) + (in & 3);
/* apply */
return sbox[x][y];
}
/* rotate 64bit number by 'rot' left */
u64 rot64left(u64 in, int rot) {
if(rot == 0) rot = 1;
@@ -70,6 +87,11 @@ u32 rot32left(u32 in, int rot) {
return (in >> (32-rot)) | (in << rot);
}
/* rotate 8bit number by 'rot' left */
byte rot8left(byte in, int rot) {
return (in >> (8-rot)) | (in << rot);
}
/* park-miller 32bit prng */
u32 _32_lcg_pm(u32 seed) {
return ((u64)seed * 48271UL) % 2147483647UL;
@@ -203,16 +225,26 @@ void diffuse_context() {
}
/* actual stream (1byte) encrypt/decrypt */
void io_loop() {
void io_loop(byte nonce) {
byte out, K[8];
int i;
w2a(combined64a(), K);
int i=0;
while(fread(&out, 1, 1, stdin) == 1) {
for(i=0; i<8; i++) out ^= sbox[K[i]]; /* apply our sbox */
fwrite(&out, 1, 1, stdout);
/* new prng round */
w2a(combined64a(), K);
for(i=0; i<8; i++) {
/* round, apply nonce to Ki and xor current input byte with the sbox of the result, repeat */
nonce ^= K[i];
out ^= apply_sbox(nonce);
/* rotate nonce left by 7 bits sometimes */
if(K[i] && K[i] % 53 == 0) {
nonce = rot8left(nonce, 7);
}
}
fwrite(&out, 1, 1, stdout);
}
fflush(stdout);
@@ -220,19 +252,20 @@ void io_loop() {
int main(int argc, char **argv) {
if(argc == 2) {
if(argc == 3) {
context = parseargs(argv[1]);
if(context == NULL) {
return 1;
}
else {
byte nonce = argv[2][0];
diffuse_context();
io_loop();
io_loop(nonce);
return 0;
}
}
else {
fprintf(stderr, "usage: twenty4 <20 byte hex key>\n");
fprintf(stderr, "usage: twenty4 <20 byte key> <1 byte nonce>\n");
return 1;
}
}