mirror of
https://codeberg.org/scip/twenty4.git
synced 2025-12-16 19:40:57 +01:00
initial commit
This commit is contained in:
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
LDFLAGS = -g
|
||||||
|
CFLAGS = -g -Wall -Wextra -Werror
|
||||||
|
DST = twenty4
|
||||||
|
OBJS = twenty4.o
|
||||||
|
|
||||||
|
all: $(DST)
|
||||||
|
|
||||||
|
$(DST): $(OBJS)
|
||||||
|
gcc $(LDFLAGS) $(OBJS) -o $(DST)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
gcc -c $(CFLAGS) $*.c -o $*.o
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(DST)
|
||||||
|
|
||||||
217
README.md
217
README.md
@@ -1,2 +1,215 @@
|
|||||||
# twenty4
|
## TWENTY4 - a fun stream cipher
|
||||||
TWENTY4 - fun stream cipher
|
|
||||||
|
*THIS IS JUST FOR LEARINING CRYPTO, DO NOT EVER USE THIS FOR ANYTHING*
|
||||||
|
|
||||||
|
This is the implementation of the fun stream cipher TWENTY4 by T.v. Dein, 09/2015.
|
||||||
|
Published under the public domain, Creative Commons Zero License. It works bytewise,
|
||||||
|
with keys between 1-256 bits in 17 rounds, uses S-Boxes and key output-feedback mode.
|
||||||
|
The cipher also works with CBC or ECB mode (sample CBC implementation included).
|
||||||
|
|
||||||
|
The name TWENTY4 is a reverence to article 20 paragraph 4 of the german constitution
|
||||||
|
which reads:
|
||||||
|
|
||||||
|
> All Germans shall have the right to resist any person seeking to
|
||||||
|
> abolish this constitutional order, if no other remedy is available.
|
||||||
|
|
||||||
|
Also, the cipher uses the contents of the german constitution as the source for its
|
||||||
|
S-Boxes.
|
||||||
|
|
||||||
|
## S-Box generation
|
||||||
|
|
||||||
|
TWENTY4 uses the german constitution (called "basic law" in germany) as
|
||||||
|
the source for S-Boxes. The EPUB version (included in sbox/ subdir)
|
||||||
|
is encrypted using AES-256-CBC with the passphrase
|
||||||
|
"grundgesetz\n". The resulting byte stream is used as the source for
|
||||||
|
S-Boxes.
|
||||||
|
|
||||||
|
The following version of the german consitution is used:
|
||||||
|
|
||||||
|
Basic Law for the Federal Republic of Germany in the revised version
|
||||||
|
published in the Federal Law Gazette Part III, classification number
|
||||||
|
100-1, as last amended by the Act of 23 December 2014
|
||||||
|
(Federal Law Gazette I p. 2438).
|
||||||
|
|
||||||
|
Linux Shell commands to generate the S-Boxes:
|
||||||
|
|
||||||
|
curl -o BJNR000010949.epub http://www.gesetze-im-internet.de/gg/BJNR000010949.epub
|
||||||
|
echo grundgesetz > BJNR000010949.pass
|
||||||
|
cat BJNR000010949.epub | openssl aes-256-cbc -kfile BJNR000010949.pass | ./gen-static-sbox
|
||||||
|
|
||||||
|
'gen-static-sbox' compiled from gen-static-sbox.c in this directory, which has SHA256
|
||||||
|
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):
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
The input key will be expanded into a 17 byte array. Maximum key size is
|
||||||
|
17 bytes (136 bit).
|
||||||
|
|
||||||
|
IV = KU[0]
|
||||||
|
for ROUND in 0..16
|
||||||
|
if KU[ROUND]
|
||||||
|
K[ROUND] = IV xor KU[ROUND]
|
||||||
|
else
|
||||||
|
K[ROUND] = IV yor KBOX[ROUND * 8];
|
||||||
|
endif
|
||||||
|
K[ROUND] = KBOX[K[ROUND]]
|
||||||
|
IV = K[ROUND]
|
||||||
|
endfor
|
||||||
|
|
||||||
|
for KROUND in 0..31
|
||||||
|
for ROUND in 0..17
|
||||||
|
K[ROUND] = IV xor (rotateleft-3(K[ROUND]) xor KBOX[rcon(IV)])
|
||||||
|
IV = K[ROUND]
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
where:
|
||||||
|
|
||||||
|
KU: input key
|
||||||
|
K[17]: initial round key array
|
||||||
|
ROUND: encryption round 1-17
|
||||||
|
KROUND: key expansion round 1-32
|
||||||
|
KBOX[256]: pre computed S-Box for key expansion
|
||||||
|
|
||||||
|
## Encryption
|
||||||
|
|
||||||
|
for INBYTE in <INSTREAM>
|
||||||
|
OUTBYTE = INBYTE
|
||||||
|
for ROUND in 0..17
|
||||||
|
OUTBYTE = OUTBYTE xor K[ROUND]
|
||||||
|
OUTBYTE = OUTBYTE xor SBOX[OUTBYTE]
|
||||||
|
OUTBYTE = rotateleft-ROUND%8(OUTBYTE)
|
||||||
|
OUTBYTE = rotateright-4(K[ROUND])
|
||||||
|
endfor
|
||||||
|
rotatekey(K, OUTBYTE)
|
||||||
|
OUTBYTE => <OUTSTREAM>
|
||||||
|
endfor
|
||||||
|
|
||||||
|
func rotatekey(K, B)
|
||||||
|
[rotate K[17] array elementy 1 to the right]
|
||||||
|
for N in 0..16:
|
||||||
|
K[N] = KBOX[K[N] xor B]
|
||||||
|
endfor
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
|
where:
|
||||||
|
|
||||||
|
K[17]: expanded key
|
||||||
|
ROUND: encryption round 1-17
|
||||||
|
INBYTE: one input byte
|
||||||
|
OUTBYTE: encrypted result for output
|
||||||
|
SBOX[256]: pre computed S-Box for encryption
|
||||||
|
|
||||||
|
|
||||||
|
## Analysis so far
|
||||||
|
|
||||||
|
While this stuff only exists for me to play around with
|
||||||
|
crypto, I tried to test the cipher a little bit. Here are
|
||||||
|
my results using a couple of statistical measurements:
|
||||||
|
|
||||||
|
I encrypted the GPLv3 contents using the key "1". To compare,
|
||||||
|
I encrypted the same file with AES-256-CBC using the same
|
||||||
|
passphrase.
|
||||||
|
|
||||||
|
|
||||||
|
### Check using analyze.c
|
||||||
|
|
||||||
|
My own measurement, see analyze.c:
|
||||||
|
|
||||||
|
File size: 35147 bytes
|
||||||
|
Char distribution: 100.000000%
|
||||||
|
Char redundancy: 0.000000%
|
||||||
|
Char entropy: 7.995333 bits/char
|
||||||
|
Compression rate: 0.000000% (35147 => 35168 bytes)
|
||||||
|
|
||||||
|
For comparision, AES result:
|
||||||
|
|
||||||
|
File size: 35168 bytes
|
||||||
|
Char distribution: 100.000000%
|
||||||
|
Char redundancy: 0.000000%
|
||||||
|
Char entropy: 7.994892 bits/char
|
||||||
|
Compression rate: 0.000000% (35168 => 35189 bytes)
|
||||||
|
|
||||||
|
## Check using ent
|
||||||
|
|
||||||
|
(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).
|
||||||
|
|
||||||
|
For comparision, AES result:
|
||||||
|
|
||||||
|
Entropy = 7.994892 bits per byte.
|
||||||
|
|
||||||
|
Optimum compression would reduce the size
|
||||||
|
of this 35168 byte file by 0 percent.
|
||||||
|
|
||||||
|
Chi square distribution for 35168 samples is 250.98, and randomly
|
||||||
|
would exceed this value 55.94 percent of the times.
|
||||||
|
|
||||||
|
Arithmetic mean value of data bytes is 127.8717 (127.5 = random).
|
||||||
|
Monte Carlo value for Pi is 3.151680601 (error 0.32 percent).
|
||||||
|
Serial correlation coefficient is 0.002014 (totally uncorrelated = 0.0).
|
||||||
|
|
||||||
|
## Check using dieharder
|
||||||
|
|
||||||
|
I fed the contents of my primary disk into TWENTY4 and its output
|
||||||
|
into diehard:
|
||||||
|
|
||||||
|
dd if=/dev/sda4 of=/dev/stdout | ./stream 1 e | dieharder -a -g 200
|
||||||
|
#=============================================================================#
|
||||||
|
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
|
||||||
|
#=============================================================================#
|
||||||
|
rng_name |rands/second| Seed |
|
||||||
|
stdin_input_raw| 1.86e+05 |2067533949|
|
||||||
|
#=============================================================================#
|
||||||
|
test_name |ntup| tsamples |psamples| p-value |Assessment
|
||||||
|
#=============================================================================#
|
||||||
|
diehard_birthdays| 0| 100| 100|0.11286983| PASSED
|
||||||
|
diehard_operm5| 0| 1000000| 100|0.14228207| PASSED
|
||||||
|
diehard_rank_32x32| 0| 40000| 100|0.08372938| PASSED
|
||||||
|
diehard_rank_6x8| 0| 100000| 100|0.47630577| PASSED
|
||||||
|
diehard_bitstream| 0| 2097152| 100|0.68878582| PASSED
|
||||||
|
diehard_opso| 0| 2097152| 100|0.36965490| PASSED
|
||||||
|
diehard_oqso| 0| 2097152| 100|0.85360068| PASSED
|
||||||
|
diehard_dna| 0| 2097152| 100|0.41389081| PASSED
|
||||||
|
diehard_count_1s_str| 0| 256000| 100|0.64198483| PASSED
|
||||||
|
diehard_count_1s_byt| 0| 256000| 100|0.48126427| PASSED
|
||||||
|
diehard_parking_lot| 0| 12000| 100|0.61281762| PASSED
|
||||||
|
diehard_2dsphere| 2| 8000| 100|0.98794548| PASSED
|
||||||
|
diehard_3dsphere| 3| 4000| 100|0.86553337| PASSED
|
||||||
|
diehard_squeeze| 0| 100000| 100|0.47837267| PASSED
|
||||||
|
diehard_sums| 0| 100| 100|0.26661852| PASSED
|
||||||
|
diehard_runs| 0| 100000| 100|0.78455791| PASSED
|
||||||
|
diehard_runs| 0| 100000| 100|0.56428921| PASSED
|
||||||
|
diehard_craps| 0| 200000| 100|0.81900152| PASSED
|
||||||
|
diehard_craps| 0| 200000| 100|0.54592338| PASSED
|
||||||
|
ctrl-c
|
||||||
|
|
||||||
|
(FIXME: I aborted here, I'll repeat that one later)
|
||||||
|
|
||||||
|
So, all those checks don't look that bad, but of course this doesn't
|
||||||
|
say much about TWENTY4. However, not THAT bad for the first cipher :)
|
||||||
|
|
||||||
|
|||||||
16
analyze/Makefile
Normal file
16
analyze/Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
LDFLAGS = -g
|
||||||
|
CFLAGS = -g -Wall -Wextra -Werror
|
||||||
|
DST = analyze
|
||||||
|
OBJS = analyze.o
|
||||||
|
|
||||||
|
all: $(DST)
|
||||||
|
|
||||||
|
$(DST): $(OBJS)
|
||||||
|
gcc $(LDFLAGS) $(OBJS) -lm -lz -o $(DST)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
gcc -c $(CFLAGS) $*.c -o $*.o
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(DST)
|
||||||
|
|
||||||
221
analyze/analyze.c
Normal file
221
analyze/analyze.c
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint32_t word;
|
||||||
|
typedef uint16_t half;
|
||||||
|
|
||||||
|
struct _bytes {
|
||||||
|
size_t len;
|
||||||
|
byte *bin;
|
||||||
|
};
|
||||||
|
typedef struct _bytes Bytes;
|
||||||
|
|
||||||
|
#define CHUNK 16384
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bytes *fetch(char *infile) {
|
||||||
|
size_t insize, p=0;
|
||||||
|
FILE *in;
|
||||||
|
Bytes *out;
|
||||||
|
|
||||||
|
if((in = fopen(infile, "rb")) == NULL) {
|
||||||
|
perror("Could not open infile");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(in, 0L, SEEK_END);
|
||||||
|
insize = ftell(in);
|
||||||
|
fseek(in, 0L, SEEK_SET);
|
||||||
|
|
||||||
|
out = malloc(sizeof(Bytes));
|
||||||
|
|
||||||
|
out->bin = malloc(insize * sizeof(byte));
|
||||||
|
out->len = insize;
|
||||||
|
memset(out->bin, 0, insize);
|
||||||
|
|
||||||
|
while (!ferror(in) && !feof(in)) {
|
||||||
|
fread(&out->bin[p++], 1, 1, in);
|
||||||
|
}
|
||||||
|
fclose(in);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t defl(FILE *source, FILE *dest, int level)
|
||||||
|
{
|
||||||
|
int ret, flush;
|
||||||
|
unsigned have;
|
||||||
|
z_stream strm;
|
||||||
|
size_t zsize;
|
||||||
|
unsigned char in[CHUNK];
|
||||||
|
unsigned char out[CHUNK];
|
||||||
|
zsize = 0;
|
||||||
|
|
||||||
|
/* allocate deflate state */
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
ret = deflateInit(&strm, level);
|
||||||
|
if (ret != Z_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* compress until end of file */
|
||||||
|
do {
|
||||||
|
strm.avail_in = fread(in, 1, CHUNK, source);
|
||||||
|
if (ferror(source)) {
|
||||||
|
(void)deflateEnd(&strm);
|
||||||
|
return Z_ERRNO;
|
||||||
|
}
|
||||||
|
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
|
||||||
|
strm.next_in = in;
|
||||||
|
|
||||||
|
/* run deflate() on input until output buffer not full, finish
|
||||||
|
compression if all of source has been read in */
|
||||||
|
do {
|
||||||
|
strm.avail_out = CHUNK;
|
||||||
|
strm.next_out = out;
|
||||||
|
ret = deflate(&strm, flush); /* no bad return value */
|
||||||
|
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
||||||
|
have = CHUNK - strm.avail_out;
|
||||||
|
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
||||||
|
(void)deflateEnd(&strm);
|
||||||
|
return Z_ERRNO;
|
||||||
|
}
|
||||||
|
zsize += have;
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
assert(strm.avail_in == 0); /* all input will be used */
|
||||||
|
|
||||||
|
/* done when last data in file processed */
|
||||||
|
} while (flush != Z_FINISH);
|
||||||
|
assert(ret == Z_STREAM_END); /* stream will be complete */
|
||||||
|
|
||||||
|
/* clean up and return */
|
||||||
|
(void)deflateEnd(&strm);
|
||||||
|
return zsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t get_zsize(char *infile) {
|
||||||
|
FILE *in;
|
||||||
|
FILE *z;
|
||||||
|
size_t zsize;
|
||||||
|
|
||||||
|
if((in = fopen(infile, "rb")) == NULL) {
|
||||||
|
perror("Could not open infile");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((z = fopen("/tmp/analyze.z", "wb")) == NULL) {
|
||||||
|
perror("Could not open zfile");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
zsize = defl(in, z, 9);
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
fclose(z);
|
||||||
|
unlink("/tmp/analyze.z");
|
||||||
|
|
||||||
|
return zsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double get_entropy(byte *source, size_t len) {
|
||||||
|
int *hist;
|
||||||
|
double H;
|
||||||
|
int wherechar[256];
|
||||||
|
int i,histlen;
|
||||||
|
|
||||||
|
histlen = 0;
|
||||||
|
H = 0;
|
||||||
|
hist = (int*)calloc(len, sizeof(int));
|
||||||
|
|
||||||
|
for(i=0; i<256; i++)
|
||||||
|
wherechar[i] = -1;
|
||||||
|
|
||||||
|
for(i=0; i<(int)len; i++){
|
||||||
|
if(wherechar[(int)source[i]] == -1) {
|
||||||
|
wherechar[(int)source[i]] = histlen;
|
||||||
|
histlen++;
|
||||||
|
}
|
||||||
|
hist[wherechar[(int)source[i]]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<histlen; i++) {
|
||||||
|
H -= (double)hist[i] / len * log2((double)hist[i] / len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return H;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double get_distribution(Bytes *in) {
|
||||||
|
int i;
|
||||||
|
byte hash[256] = {0};
|
||||||
|
double chars = 0;
|
||||||
|
|
||||||
|
for (i=0; i<(int)in->len; i++) {
|
||||||
|
hash[in->bin[i]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<256; i++) {
|
||||||
|
if(hash[i]) {
|
||||||
|
chars++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void analyze(char *infile) {
|
||||||
|
double chars = 0, dist, red, entropy, zrate;
|
||||||
|
size_t zsize;
|
||||||
|
Bytes *in = fetch(infile);
|
||||||
|
|
||||||
|
entropy = get_entropy(in->bin, in->len);
|
||||||
|
chars = get_distribution(in);
|
||||||
|
zsize = get_zsize(infile);
|
||||||
|
|
||||||
|
dist = chars / 2.56;
|
||||||
|
red = 100 - dist;
|
||||||
|
zrate = zsize > in->len ? 0 : 100 - (zsize / (in->len / 100));
|
||||||
|
|
||||||
|
fprintf(stdout,
|
||||||
|
" File size: %ld bytes\n"
|
||||||
|
"Char distribution: %lf%%\n"
|
||||||
|
" Char redundancy: %lf%%\n"
|
||||||
|
" Char entropy: %lf bits/char\n"
|
||||||
|
" Compression rate: %lf%% (%ld => %ld bytes)\n",
|
||||||
|
in->len, dist, red, entropy, zrate, in->len, zsize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_chars_hex(Bytes *in) {
|
||||||
|
int i;
|
||||||
|
for (i=0; i<(int)in->len; i++) {
|
||||||
|
fprintf(stdout, "%02x\n", in->bin[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if(argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: analyze <file>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
analyze(argv[1]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
32
analyze/analyze.sh
Executable file
32
analyze/analyze.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
an=./analyze
|
||||||
|
cr=./stream
|
||||||
|
|
||||||
|
mkdir -p t
|
||||||
|
|
||||||
|
jot () {
|
||||||
|
r=$1;
|
||||||
|
if test -z "$r"; then
|
||||||
|
echo "jot <rounds>";
|
||||||
|
else
|
||||||
|
perl -e "foreach(0..$r){print \"\$_\n\";}";
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
./prepare-analyze
|
||||||
|
|
||||||
|
for L in `jot 255`; do
|
||||||
|
XL=`printf "%02x" $L`
|
||||||
|
clear="t/$XL.clear"
|
||||||
|
for K in `jot 255`; do
|
||||||
|
XK=`printf "%02x" $K`
|
||||||
|
cipher="t/$XLx$XK.cipher"
|
||||||
|
cat $clear | $cr 0x$K e > $cipher
|
||||||
|
echo -n "$XL w/ $XK: "
|
||||||
|
$an $cipher 1
|
||||||
|
rm -f $cipher
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
BIN
sbox/BJNR000010949.epub
Normal file
BIN
sbox/BJNR000010949.epub
Normal file
Binary file not shown.
1
sbox/BJNR000010949.pass
Normal file
1
sbox/BJNR000010949.pass
Normal file
@@ -0,0 +1 @@
|
|||||||
|
grundgesetz
|
||||||
19
sbox/Makefile
Normal file
19
sbox/Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
LDFLAGS = -g
|
||||||
|
CFLAGS = -g -Wall -Wextra -Werror
|
||||||
|
DST = gen-static-sbox
|
||||||
|
OBJS = gen-static-sbox.o
|
||||||
|
|
||||||
|
all: $(DST)
|
||||||
|
|
||||||
|
$(DST): $(OBJS)
|
||||||
|
gcc $(LDFLAGS) $(OBJS) -o $(DST)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
gcc -c $(CFLAGS) $*.c -o $*.o
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(DST)
|
||||||
|
|
||||||
|
|
||||||
|
sboxes:
|
||||||
|
cat BJNR000010949.epub | openssl aes-256-cbc -kfile BJNR000010949.pass | ./$(DST)
|
||||||
58
sbox/gen-static-sbox.c
Normal file
58
sbox/gen-static-sbox.c
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint32_t word;
|
||||||
|
typedef uint16_t half;
|
||||||
|
|
||||||
|
#define MAX 4096
|
||||||
|
|
||||||
|
void dump256(byte *hash) {
|
||||||
|
int i, b = 1;
|
||||||
|
|
||||||
|
for(i=0; i<256; i++) {
|
||||||
|
fprintf(stderr, "0x%02x, ", hash[i]);
|
||||||
|
if(b == 16) {
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
b = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
byte raw[MAX];
|
||||||
|
byte hash[256] = {0}, reg[256] = {0}, out;
|
||||||
|
int i, b=0, has=0;
|
||||||
|
|
||||||
|
fread(raw, MAX, 1, stdin);
|
||||||
|
|
||||||
|
memset(hash, 0, 256);
|
||||||
|
|
||||||
|
for (i=0; i<MAX; i++) {
|
||||||
|
out = raw[i];
|
||||||
|
if(reg[out] == 0) {
|
||||||
|
reg[out]++;
|
||||||
|
hash[b++] = out;
|
||||||
|
has++;
|
||||||
|
}
|
||||||
|
if(has == 256) {
|
||||||
|
dump256(hash);
|
||||||
|
has = b = 0;
|
||||||
|
memset(hash, 0, 256);
|
||||||
|
memset(reg, 0, 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fwrite(hash, 256, 1, stdout);
|
||||||
|
fprintf(stderr, "done\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
308
twenty4.c
Normal file
308
twenty4.c
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
******* THIS IS JUST FOR LEARINING CRYPTO, DO NOT EVER USE THIS FOR ANYTHING *******
|
||||||
|
|
||||||
|
This is the implementation of the fun stream cipher TWENTY4 by Thomas von Dein, 09/2015.
|
||||||
|
Published under the public domain, Creative Commons Zero License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint32_t word;
|
||||||
|
typedef uint16_t half;
|
||||||
|
|
||||||
|
const byte kbox[] = {
|
||||||
|
0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0xdf, 0x40, 0xc1, 0x9d, 0x46, 0x33, 0x45, 0x92, 0x95,
|
||||||
|
0xd8, 0x24, 0xf5, 0x1c, 0xe0, 0x29, 0xff, 0xa3, 0x71, 0x6f, 0x35, 0x2e, 0x4b, 0x0d, 0xa7, 0x5d,
|
||||||
|
0x97, 0xe1, 0x98, 0x58, 0x2b, 0xc4, 0xae, 0xe3, 0xec, 0xb8, 0x38, 0xee, 0x91, 0x2c, 0xb4, 0xa0,
|
||||||
|
0xc6, 0x34, 0x1f, 0x57, 0x0e, 0xc3, 0x4f, 0xb9, 0x80, 0x21, 0x5b, 0x06, 0xf6, 0x87, 0xfa, 0x5e,
|
||||||
|
0xe7, 0xda, 0xce, 0xdd, 0x23, 0xe9, 0x03, 0x39, 0xa5, 0x8e, 0xb6, 0xca, 0x3c, 0x7a, 0x44, 0x2d,
|
||||||
|
0x07, 0xcf, 0x1b, 0xd0, 0x94, 0x85, 0xc5, 0x20, 0xaa, 0x81, 0xc9, 0xb7, 0x2f, 0xfb, 0xb2, 0x50,
|
||||||
|
0x54, 0xf0, 0x14, 0xd9, 0x00, 0x67, 0x15, 0x9f, 0xa2, 0x02, 0x93, 0xcc, 0xdb, 0x8d, 0x30, 0x78,
|
||||||
|
0xb1, 0x7b, 0x19, 0xc0, 0x43, 0x6b, 0xbb, 0x2a, 0x3b, 0x4d, 0xe4, 0x08, 0x12, 0x90, 0x32, 0xef,
|
||||||
|
0xe8, 0x5a, 0xac, 0xf4, 0x8c, 0xe2, 0x4e, 0x6d, 0xaf, 0x66, 0xf8, 0xbc, 0x36, 0x72, 0x01, 0x1e,
|
||||||
|
0x68, 0x37, 0x59, 0x51, 0xa6, 0x7c, 0xbe, 0x86, 0x8a, 0x8b, 0xfe, 0x0a, 0x05, 0x52, 0x76, 0x27,
|
||||||
|
0x69, 0x18, 0x22, 0x63, 0x42, 0x4a, 0xad, 0x10, 0xe5, 0xa1, 0xc8, 0xeb, 0xb0, 0x09, 0x6a, 0x4c,
|
||||||
|
0x16, 0xf7, 0xde, 0xfc, 0x7f, 0x7d, 0xdc, 0x99, 0xbd, 0x7e, 0x26, 0xcd, 0xba, 0xc2, 0xa8, 0x04,
|
||||||
|
0x0f, 0x3e, 0x82, 0x1d, 0x89, 0xb5, 0x31, 0xb3, 0x47, 0x6e, 0xf3, 0x0b, 0xd3, 0x84, 0x49, 0x0c,
|
||||||
|
0x3d, 0xd5, 0x9a, 0xd6, 0x9e, 0xd7, 0x8f, 0xa9, 0x79, 0xd4, 0x48, 0x9b, 0x55, 0x56, 0xcb, 0x3a,
|
||||||
|
0xf9, 0xfd, 0xd2, 0xe6, 0x75, 0x1a, 0x11, 0xf2, 0xa4, 0x5c, 0x96, 0x13, 0xea, 0xd1, 0xbf, 0x60,
|
||||||
|
0x28, 0xab, 0x9c, 0x77, 0x83, 0x62, 0x17, 0x41, 0x70, 0x25, 0xf1, 0x3f, 0x88, 0x73, 0xc7, 0xed,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const byte 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,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
byte revsbox[256];
|
||||||
|
|
||||||
|
#define K_HASH_ROUNDS 32
|
||||||
|
#define S_BOX_ROUNDS 17
|
||||||
|
|
||||||
|
|
||||||
|
byte rot8left(byte in, int rot) {
|
||||||
|
return (in >> (8-rot)) | (in << rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte rot8right(byte in, int rot) {
|
||||||
|
return (in << (8-rot)) | (in >> rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printbits(byte v) {
|
||||||
|
int i;
|
||||||
|
for(i = 7; i >= 0; i--) fprintf(stderr, "%c", '0' + ((v >> i) & 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump8(char *n, byte d) {
|
||||||
|
fprintf(stderr, "%s: %02x ", n, d);
|
||||||
|
printbits(d);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpN(char *n, byte *d, size_t s) {
|
||||||
|
int l = strlen(n) + 9;
|
||||||
|
fprintf(stderr, "%s (%04ld): ", n, s);
|
||||||
|
size_t i;
|
||||||
|
int c;
|
||||||
|
for (i=0; i<s; ++i) {
|
||||||
|
fprintf(stderr, "%02x ", d[i]);
|
||||||
|
if(i % 8 == 7 && i > 0) {
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
for(c=0; c<l; ++c)
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for decryption */
|
||||||
|
void reverse_sbox() {
|
||||||
|
int i;
|
||||||
|
for(i=0; i<256; i++)
|
||||||
|
revsbox[sbox[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte getiv() {
|
||||||
|
FILE *RAND;
|
||||||
|
byte rand;
|
||||||
|
|
||||||
|
if((RAND = fopen("/dev/urandom", "rb")) == NULL) {
|
||||||
|
perror("Could not open /dev/urandom");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fread(&rand, 1, 1, RAND) != 1) {
|
||||||
|
perror("Could not read from /dev/urandom");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(RAND);
|
||||||
|
|
||||||
|
return rand;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte rcon(byte in) {
|
||||||
|
byte c=1;
|
||||||
|
if(in == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while(in != 1) {
|
||||||
|
byte b;
|
||||||
|
b = c & 0x80;
|
||||||
|
c <<= 1;
|
||||||
|
if(b == 0x80) {
|
||||||
|
c ^= 0x1b;
|
||||||
|
}
|
||||||
|
in--;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we use rounds * 8bit sub keys expanded from
|
||||||
|
given password */
|
||||||
|
void keyhash(char *pw, byte *hash) {
|
||||||
|
byte iv;
|
||||||
|
int i, round;
|
||||||
|
unsigned int HEX;
|
||||||
|
size_t pwlen;
|
||||||
|
|
||||||
|
if(strncmp(pw, "0x", 2) == 0) {
|
||||||
|
/* hex pw */
|
||||||
|
sscanf(pw, "0x%02x", &HEX);
|
||||||
|
pw[0] = (byte)HEX;
|
||||||
|
pwlen = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pwlen = strlen(pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
iv = kbox[(byte)pw[0]];
|
||||||
|
|
||||||
|
/* stretch pw */
|
||||||
|
for(i=0; i<S_BOX_ROUNDS; i++) {
|
||||||
|
if((size_t)i < pwlen)
|
||||||
|
hash[i] = iv ^ pw[i];
|
||||||
|
else
|
||||||
|
hash[i] = iv ^ kbox[i*8];
|
||||||
|
|
||||||
|
hash[i] = kbox[hash[i]];
|
||||||
|
iv = hash[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* diffuse and confuse hash */
|
||||||
|
for(round=0; round<K_HASH_ROUNDS; round++) {
|
||||||
|
for(i=0; i<S_BOX_ROUNDS; i++) {
|
||||||
|
hash[i] = iv ^ (rot8left(hash[i], 3) ^ kbox[rcon(iv)]);
|
||||||
|
iv = hash[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(byte a[], int sz) {
|
||||||
|
int i, j;
|
||||||
|
for (i = 0, j = sz; i < j; i++, j--) {
|
||||||
|
byte tmp = a[i];
|
||||||
|
a[i] = a[j];
|
||||||
|
a[j] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rotate(byte array[], int size, int amt) {
|
||||||
|
if (amt < 0)
|
||||||
|
amt = size + amt;
|
||||||
|
reverse(array, size-amt-1);
|
||||||
|
reverse(array+size-amt, amt-1);
|
||||||
|
reverse(array, size-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rotatekey(byte *key, byte feedback) {
|
||||||
|
rotate(key, S_BOX_ROUNDS, 1);
|
||||||
|
int i;
|
||||||
|
for(i=0; i<S_BOX_ROUNDS; i++) {
|
||||||
|
key[i] = kbox[key[i] ^ feedback];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* actual stream cipher:
|
||||||
|
- xor with round key
|
||||||
|
- apply sbox
|
||||||
|
- rotate left by (round mod 8) bits
|
||||||
|
- xor with (round key rotated left by 4 bits [halfes reversed])
|
||||||
|
*/
|
||||||
|
byte bytebox(byte in, byte *key, int encrypt) {
|
||||||
|
int i;
|
||||||
|
byte out = in;
|
||||||
|
|
||||||
|
if(encrypt) {
|
||||||
|
for(i=0; i<S_BOX_ROUNDS; i++) {
|
||||||
|
out ^= key[i];
|
||||||
|
out = sbox[out];
|
||||||
|
out = rot8left(out, i%8);
|
||||||
|
out ^= rot8right(key[i], 4);
|
||||||
|
}
|
||||||
|
rotatekey(key, out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(i=S_BOX_ROUNDS-1; i>= 0; i--) {
|
||||||
|
out ^= rot8left(key[i], 4);
|
||||||
|
out = rot8right(out, i%8);
|
||||||
|
out = revsbox[out];
|
||||||
|
out ^= key[i];
|
||||||
|
}
|
||||||
|
rotatekey(key, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* work on stdin and stdout */
|
||||||
|
int handleio(byte *key, int encrypt) {
|
||||||
|
byte in, out;
|
||||||
|
|
||||||
|
while (fread(&in, 1, 1, stdin) == 1) {
|
||||||
|
out = bytebox(in, key, encrypt);
|
||||||
|
fwrite(&out, 1, 1, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* work on stdin and stdout, in CBC 8bit mode */
|
||||||
|
int cbc_handleio(byte *key, int encrypt) {
|
||||||
|
byte in, out, iv;
|
||||||
|
|
||||||
|
if(encrypt) {
|
||||||
|
iv = getiv();
|
||||||
|
fwrite(&iv, 1, 1, stdout);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fread(&iv, 1, 1, stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fread(&in, 1, 1, stdin) == 1) {
|
||||||
|
if(encrypt) {
|
||||||
|
out = bytebox(iv ^ in, key, encrypt);
|
||||||
|
iv = out;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out = iv ^ bytebox(in, key, encrypt);
|
||||||
|
iv = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(&out, 1, 1, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
byte key[S_BOX_ROUNDS];
|
||||||
|
int encrypt;
|
||||||
|
|
||||||
|
if(argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: stream <passwd> <e|n>\ne=encrypt, n=decrypt\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encrypt = 0;
|
||||||
|
|
||||||
|
if(strcmp(argv[2], "e") == 0)
|
||||||
|
encrypt = 1;
|
||||||
|
|
||||||
|
reverse_sbox();
|
||||||
|
|
||||||
|
keyhash(argv[1], key);
|
||||||
|
|
||||||
|
return handleio(key, encrypt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user