Cryptography-Digest Digest #122, Volume #12      Wed, 28 Jun 00 03:13:01 EDT

Contents:
  [WARNING: BIG!!!] Updated paper (1.0.1/Jun 27 2000) (Runu Knips)

----------------------------------------------------------------------------

Date: Wed, 28 Jun 2000 09:01:42 +0200
From: Runu Knips <[EMAIL PROTECTED]>
Subject: [WARNING: BIG!!!] Updated paper (1.0.1/Jun 27 2000)


/*
                         PARANOIA
                   Runu Knips Jun 21 2000


Introduction

Paranoia is a block cipher. It works with 256 bit blocks, and uses a
feistel-like structure, which has 48 rounds, or 6 rounds per each of
the 8 32 bit values in the block. It accepts up to 2048 bits of key
material. Using more or less key bits doesn't slow down or speed up
anything. To resist brute force attacks, one should use at least
keys of 80 bits at the moment.

Paranoia is free, and as far as I know (which might not be very much),
not subject to any patents.

Its name is derived from the fact that it is that slow; it only reaches
arround 1.5 MB/s on my AMD KII 300, in a practical test on a large
disk file. I just thought to use this cipher you have to have paranoia.
At least the algorithm here guarantees a very high degree of diffusion,
and it is completely based on algorithmic operations. There are no
tables which might contain some trapdoor.


Key schedule

The key schedule is again a avalanche addition, as with my previous
cipher, Whirl128.

An array of 64 elements, each a 32 unsigned value, is first initialized
with zeros, then we put the bytes of the key in network order at the
start of it. After this, we perform the avalanche addition, which
looks like this in pseudo code:

        for rounds in [1..3] do
                for i in [0..63] do
                        L[i] := L[i] + Pw
                                + L[(i+3) MOD 64]
                                + ROTL (L[(i+11) MOD 64], 3)
                                + ROTL (L[(i+31) MOD 64], 15)
                                + ROTL (L[(i+53) MOD 64], 13)
                                + ROTL (L[(i+57) MOD 64], 7)
                                + ROTL (L[(i+62) MOD 64], 1);

Pw is defined to be the first 31 postcomma bits of pi, plus a
lsb of 1. It should just fight against evil zero values (once the
whole thing is zero, there would be no way out of it anymore).

MOD is the modulo or remainder operation, the rest of an integer
division.

ROTL, often written as '<<<', is a left rotation, i.e. in the
expression 'ROTL (n, x)', or 'n <<< x', one shifts the bits of
'n' 'x' times to the left, and insert in each step the bit which
gets lost at the top of the number into the bottom again. This
way all the bits of the number change their position, but none
gets lost, like in the pure shift operation '<<' (or '>>').

Writing  ROTL (and ROTR) instead of '<<<' (and '>>>') in
mathematical expressions is uncommon, but below we will define
an operation which is very much like rotation, and we can express
the relation between these two operations better if we use the
uncommon way.

After the loop, the first 48 array elements are copied into the
array of round transformation data T, the rest, 16 elements, is
copied into the array of whitening data W.

The reason for this design was the idea to spread the bits of
the input over the whole array, i.e. every bit of the array
depends on all bits of the input. The fixed values for the
relative offsets and shift offsets have been found using some
common sense and empiric tests which values would influence all
bits of the resulting array very fast.


Encryption process

Paranoia works with 256 bit blocks, which are split into 8 32 bit
values. First (and last) whitening is performed.

        a := I[0] XOR W[0]; b := I[1] XOR W[1];
        c := I[2] XOR W[2]; d := I[3] XOR W[3];
        e := I[4] XOR W[4]; f := I[5] XOR W[5];
        g := I[6] XOR W[6]; h := I[7] XOR W[7];

XOR is bitwise operation, for each input bit pair of this
function, the result is one if they are not equal.

The last step of the algorithm is in full analogy to the first
with W[8..15].

The encryption part of the algorithm is a 48 times loop over the
keyvalues. In each loop 7 values and 2 keyschedule parts are
used to modify the last value.

        for i in [0..47] do (
                u := T[47-i] + h;

                a := a + b + Pw;
                a := BRTL3 (a, u >> 26);
                a := a XOR c;
                a := ROTL (a, u >> 10);
                a := BRTL4 (a, u >> 19);
                a := a + d;
                a := BRTL2 (a, u >> 29);
                a := a XOR e;
                a := ROTL (a, u >> 5);
                a := BRTL3 (a, u >> 23);
                a := a + f;
                a := BRTL4 (a, u >> 15);
                a := a XOR g;
                a := ROTL (a, u);
                a := BRTL1 (a, u >> 31);
                a := a + T[i];

                u := a; a := b; b := c; c := d; d := e;
                        e := f; f := g; g := h; h := u;
        )

All operations have been explained (or do you need to get
addition explained ?) before except the BRT family. Pw
is added again to fight against zero values.

BRT stands for "Bit rotations". The best way to explain
BRTn is to describe how I found it. The basic problem
with the well-known RC5 algorithm was that it only uses
5 bits of the shift argument in every round. Of the (32!)
possible bit transformations of a 32 bit number n, it
allows only 2**5 == 32 in each round. My idea was to find
bit permutations which uses more bits.

A general network which allows all possible bit
permutations can be constructed as follows: first we have
16 2 bit rotation units. A 2 bit rotation is either the
identity, or an exchange. The output of 2 such units is
then again input to one of 8 4 bit rotation units, which
again output to 4 8 bit rotation units, which again
output to 2 16 bit rotation units, which then output
to the central 32 bit rotation unit. That one is used
to distribute the bits between two other 16 bit rotation
units, which by themselves output each to two 8 bit
rotation units and so on. One needs 2*(16*1+8*2+4*3+2*4)
+ 5 = 109 bits to paramerize this network, which is of
course still very redundant; i.e. different inputs might
result into the same bit mutation.

Implementing a network like this in software is very
expensive. And it would only realize diffusion, not
confusion, so it alone cannot form a secure cipher. So we
have to modify the above cipher somehow that it might be
implemented efficiently in software, and add some confusion
mechanism. The idea is to use the same shift value for each
rotation unit of a given size. This way one can realize
such a network with 2*(1+2+3+4)+5 = 25 bits.

BRT is the operation realizing these parallel bit rotations.
It is still expensive compared to addition or even normal
dynamic rotation; but it is far cheaper than realizing
the full network.

BRTR is the inverse function to BRTL, just like ROTR is the
inverse to ROTL. The number specifies the number of bits
used to parameterize the function. So ROTL could also be
written as "BRTL5" (but we don't do that).

The rest of the design of a round function was derived from
the fact that all BRT functions are of limited use to
spread bits compared to ROT, which allows all possible
positions for any given bit. So there are 3 ROT operations
in a round, plus two BRT4 and BRT3 ops, plus one BRT2 and
BRT1 op. Each operation has the maximum distance to the
equal operation; and each BRT* op is separated from all
other BRT ops by an additon or a ROT plus XOR.

This way we have defined a bit rotation which can be
parameterized with 32 bits. Of course different parameters
will result in the same bit permutations; but the diffusion
is far stronger than with a simple rotation alone. And
because we perform add or xor with another value after
every step each different path through the network tends
to have a different result.


Appendix A: Test vectors.
=========================

All values are displayed as hexadecimal.

Warning: all values are shown in network order. If you have
a little endian architecture such as the x86 or the alpha, and
your values are 0xghefcdab while the values here are 0xabcdefgh
you only get the values in wrong order (for example, if you
view the registers itself in the debugger).

Format:
        K - key (256 bit / 32 byte)
        --------------
           Key schedule (48 32 bit values)
           ----------
           Whitening data (16 32 bit values)
        -------------
        I - input data (plaintext, 8 32 bit values)
        ------------
        0..6 - round data (before first round to after last round)
        ------------
        O - output data (ciphertext
        ------------
        6..0 - inverse round data from decyphering
        ------------
        C - check (plaintext, should be equal to input !)



K: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
   aec3101e 468afa79 3e484218 9ba649bb 30ed31d6 5bd5867b 8a8c143c
b0343330
   b9f3aa1d 8c587cc4 51810196 8bbae226 b49a8d37 a82a1c4d c6c2b9e0
b38bc68b
   22f81772 b1361d01 f43abd0b 0281ad5f 22257d14 21cdadda 0a23fc53
a7f62576
   c0309b28 6b122f2a 155b7ca4 d59c8c89 6c8958a1 53528d7c e10f5da2
56d873e8
   53243ee9 e31043db 4b4d9364 9d6eebfc c0a9e354 15ad69c4 287bfc57
a82034a5
   8c30599e 8b9ec7e3 36921ec9 a09e32f9 37ee86b5 d63bf14c 7a6e71d4
d6efd46b
  
=======================================================================
   3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
   a218ede6 3b96cf18 05136fab 3b667b47 801b28b8 8922fe97 4a610724
382bc333
==========================================================================
I: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
0: 3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
1: 24deee8c eb1aef38 eb2f668e 5c0d25c3 a5c1e6f0 6706ac0b 25f27b3e
9ec5a998
2: e1708b49 fbb5f6ba 40daf77a bb1babdd 02b32625 a514b36b 9dbfabc7
c7af0565
3: efc465a6 26985553 45fa760c 8aa2ae6a 8a0aabbd 9de6e150 e4c09434
32f238a6
4: d1edebf9 d149eca1 24449eeb d78523fd 688f2f45 5bf8334d 2757c8e1
ea12a7f9
5: 3768425f ae6ed4a2 9ffba2c1 71055fff 8d170dea cc56ed7b 3f58796c
845ce5d7
6: 7ff7fc3a 76503734 4cc0785b d8004803 5dce4c17 06e7a17e 540e604e
c1bf98d4
==========================================================================
O: ddef11dc 4dc6f82c 49d317f0 e3663344 ddd564af 8fc55fe9 1e6f676a
f9945be7
==========================================================================
6: 7ff7fc3a 76503734 4cc0785b d8004803 5dce4c17 06e7a17e 540e604e
c1bf98d4
5: 3768425f ae6ed4a2 9ffba2c1 71055fff 8d170dea cc56ed7b 3f58796c
845ce5d7
4: d1edebf9 d149eca1 24449eeb d78523fd 688f2f45 5bf8334d 2757c8e1
ea12a7f9
3: efc465a6 26985553 45fa760c 8aa2ae6a 8a0aabbd 9de6e150 e4c09434
32f238a6
2: e1708b49 fbb5f6ba 40daf77a bb1babdd 02b32625 a514b36b 9dbfabc7
c7af0565
1: 24deee8c eb1aef38 eb2f668e 5c0d25c3 a5c1e6f0 6706ac0b 25f27b3e
9ec5a998
0: 3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
==========================================================================
C: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000


K: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
   aec3101e 468afa79 3e484218 9ba649bb 30ed31d6 5bd5867b 8a8c143c
b0343330
   b9f3aa1d 8c587cc4 51810196 8bbae226 b49a8d37 a82a1c4d c6c2b9e0
b38bc68b
   22f81772 b1361d01 f43abd0b 0281ad5f 22257d14 21cdadda 0a23fc53
a7f62576
   c0309b28 6b122f2a 155b7ca4 d59c8c89 6c8958a1 53528d7c e10f5da2
56d873e8
   53243ee9 e31043db 4b4d9364 9d6eebfc c0a9e354 15ad69c4 287bfc57
a82034a5
   8c30599e 8b9ec7e3 36921ec9 a09e32f9 37ee86b5 d63bf14c 7a6e71d4
d6efd46b
  
=======================================================================
   3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
   a218ede6 3b96cf18 05136fab 3b667b47 801b28b8 8922fe97 4a610724
382bc333
==========================================================================
I: 80000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
0: bf704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
1: 22deea80 d8139e73 775c10d5 69898af7 e4015ed7 98fa5d22 62cff97a
543c655a
2: 98d9b9ab 1cef9442 cfc7b962 78b1615e 0841a8bb 517d278b 848f6d2e
1707b05f
3: 7d807133 e3852c1a c79abb18 71383cc5 45f4d546 b3ffea9c f0479840
ecce9505
4: 93b3fc1e 87ade6ac 27fd3336 78818a2c 17d1019b e6fc5eca 9a7e8d87
49010ccb
5: c15ed102 332db2fc b7673007 0637255f 8f0ecdd4 837e5fc2 55b01177
ce4e0e4c
6: 86449457 a24a5d6e 7343190b 23b2f562 d3e7f600 b2b94baf 41b7b28e
9e6ff3e6
==========================================================================
O: 245c79b1 99dc9276 765076a0 18d48e25 53fcdeb8 3b9bb538 0bd6b5aa
a64430d5
==========================================================================
6: 86449457 a24a5d6e 7343190b 23b2f562 d3e7f600 b2b94baf 41b7b28e
9e6ff3e6
5: c15ed102 332db2fc b7673007 0637255f 8f0ecdd4 837e5fc2 55b01177
ce4e0e4c
4: 93b3fc1e 87ade6ac 27fd3336 78818a2c 17d1019b e6fc5eca 9a7e8d87
49010ccb
3: 7d807133 e3852c1a c79abb18 71383cc5 45f4d546 b3ffea9c f0479840
ecce9505
2: 98d9b9ab 1cef9442 cfc7b962 78b1615e 0841a8bb 517d278b 848f6d2e
1707b05f
1: 22deea80 d8139e73 775c10d5 69898af7 e4015ed7 98fa5d22 62cff97a
543c655a
0: bf704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
==========================================================================
C: 80000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000


K: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
   aec3101e 468afa79 3e484218 9ba649bb 30ed31d6 5bd5867b 8a8c143c
b0343330
   b9f3aa1d 8c587cc4 51810196 8bbae226 b49a8d37 a82a1c4d c6c2b9e0
b38bc68b
   22f81772 b1361d01 f43abd0b 0281ad5f 22257d14 21cdadda 0a23fc53
a7f62576
   c0309b28 6b122f2a 155b7ca4 d59c8c89 6c8958a1 53528d7c e10f5da2
56d873e8
   53243ee9 e31043db 4b4d9364 9d6eebfc c0a9e354 15ad69c4 287bfc57
a82034a5
   8c30599e 8b9ec7e3 36921ec9 a09e32f9 37ee86b5 d63bf14c 7a6e71d4
d6efd46b
  
=======================================================================
   3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850b
   a218ede6 3b96cf18 05136fab 3b667b47 801b28b8 8922fe97 4a610724
382bc333
==========================================================================
I: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000001
==========================================================================
0: 3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850a
1: 6d4c5570 e0427a40 7f843365 d4f0dde4 30c9a57a 22042d3f e85ddfd5
018dfcb1
2: 4161f77e 03153225 5fef90cb 445b617d 1a66aaab ba4cf4c1 80481e88
9a730ca5
3: 5c18c409 87095588 24f5f5b2 8f65da7b fea2ddd1 80cbab65 0b0f9b49
87acc1d5
4: 3cf5cc08 2294ce9c 86b1498c 4a4bd8c2 237b51b7 373bcd46 ff6e78ec
868aa364
5: a4747df4 87b5c1a0 ca068e82 2ffe1a9f 8783598f 354838a7 81e48a1c
2ad5f6c8
6: 4b0ddc1f f97eba87 033a9f12 cda93c62 d5f7f041 5991d437 7b0697c4
81c1e6f0
==========================================================================
O: e91531f9 c2e8759f 0629f0b9 f6cf4725 55ecd8f9 d0b32aa0 316790e0
b9ea25c3
==========================================================================
6: 4b0ddc1f f97eba87 033a9f12 cda93c62 d5f7f041 5991d437 7b0697c4
81c1e6f0
5: a4747df4 87b5c1a0 ca068e82 2ffe1a9f 8783598f 354838a7 81e48a1c
2ad5f6c8
4: 3cf5cc08 2294ce9c 86b1498c 4a4bd8c2 237b51b7 373bcd46 ff6e78ec
868aa364
3: 5c18c409 87095588 24f5f5b2 8f65da7b fea2ddd1 80cbab65 0b0f9b49
87acc1d5
2: 4161f77e 03153225 5fef90cb 445b617d 1a66aaab ba4cf4c1 80481e88
9a730ca5
1: 6d4c5570 e0427a40 7f843365 d4f0dde4 30c9a57a 22042d3f e85ddfd5
018dfcb1
0: 3f704779 29ec6246 59dd7cb6 6a7332de 35a4b37e 7002570d 2d73edd4
0a7b850a
==========================================================================
C: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000001


K: 80000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
   1b421172 03e94594 34aa6062 dda408f0 8b7764c1 74bb6c87 e97e2120
e0ad485f
   95e34547 cf367a02 bba86d78 c2d56581 9457f6ac dfabb8bc 797c22ea
d289a0b9
   a7faf766 0f3da195 1ecf818f 550156c2 ff558510 7614ed07 55a55ecc
385133bc
   db9edf1e 42adc769 eec4cb83 cd837401 273f406c 072bdf3a 37005821
ff4c584b
   5c3fd759 77c43fc8 416f6997 3d2225f5 8e00720f 34813b64 55308168
e6004930
   f2b48af4 1e1fa0bf fe3e6366 7b0d77d5 babf6501 29625e8d 74725197
b17358f3
  
=======================================================================
   8dd3f1e2 d98ba1a8 51dd93a3 727a8dbf 3343b302 2ba7db1f 60d2d02c
6bfad20c
   a04d61f1 5666eccf d55466ed c3a77df9 19c22f14 ac33c726 b81ba971
d5716514
==========================================================================
I: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
0: 8dd3f1e2 d98ba1a8 51dd93a3 727a8dbf 3343b302 2ba7db1f 60d2d02c
6bfad20c
1: 46f14f3f 2ef89e35 720e78fa fcc255ea 54efb1f4 2de50544 2ce090c5
eda3e537
2: d56710e2 fd58b3ab 8b75a15f 33796900 d7defe74 54ca362d 95a903e0
5153a5de
3: 5726ea9b 2f5665c8 3eb14b38 e4b2ee30 6cfd816a f196991c ceae4205
f927fae2
4: a8ff9633 10e5a0cd ea4429bf eaa46009 f9b90dae 4675d645 a295762f
bf0c2839
5: 32622f2f a45f8784 66fe0f6d 1d3cc13a 10754162 b9d02a19 8a20ba61
0bc6351d
6: 5ae649cc fcb8b156 81458752 80bd28e4 99d94117 72ad9502 24ae9bee
88a22acc
==========================================================================
O: faab283d aade5d99 5411e1bf 431a551d 801b6e03 de9e5224 9cb5329f
5dd34fd8
==========================================================================
6: 5ae649cc fcb8b156 81458752 80bd28e4 99d94117 72ad9502 24ae9bee
88a22acc
5: 32622f2f a45f8784 66fe0f6d 1d3cc13a 10754162 b9d02a19 8a20ba61
0bc6351d
4: a8ff9633 10e5a0cd ea4429bf eaa46009 f9b90dae 4675d645 a295762f
bf0c2839
3: 5726ea9b 2f5665c8 3eb14b38 e4b2ee30 6cfd816a f196991c ceae4205
f927fae2
2: d56710e2 fd58b3ab 8b75a15f 33796900 d7defe74 54ca362d 95a903e0
5153a5de
1: 46f14f3f 2ef89e35 720e78fa fcc255ea 54efb1f4 2de50544 2ce090c5
eda3e537
0: 8dd3f1e2 d98ba1a8 51dd93a3 727a8dbf 3343b302 2ba7db1f 60d2d02c
6bfad20c
==========================================================================
C: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000


K: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000001
==========================================================================
   087d3d7d 3cbe3215 0d2ef664 62d634d5 bb75e391 dbe522b9 b82f7faa
4fa48309
   b21890ba 9f03ae2e 8a083dd9 e79bee06 459ec5b8 d9a73fd6 29c07a55
e4695252
   0b08c521 1088e66b 211a1071 8739b8d0 c5766816 3090c99e 8c9ebac7
6d78f2ee
   9bf83ae4 06e60831 b3cafa23 da2f1e71 b39ab84b 733c3f67 a9eab186
fcf6f1d4
   da710418 1a75b9aa 120f4ac4 3f298fed 303c307d 8062cd16 d1988bc1
02c3f1df
   9bacc8d2 f4d3707a 7b5ea51c 7da9869a 94dacd76 3d595f9a 37cd7fc0
5f745d28
  
=======================================================================
   65bd74f0 d7330f40 e59b4633 eedf9344 7bbef6a5 01982c42 2933c4c6
d49ef06e
   b31037b3 672684f2 c84ff03d 5412185c e6f2f789 64d27cc7 43763c0a
9494e13e
==========================================================================
I: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
==========================================================================
0: 65bd74f0 d7330f40 e59b4633 eedf9344 7bbef6a5 01982c42 2933c4c6
d49ef06e
1: 7d3857c6 7d7d1934 e0127b4a 823e3731 405113f4 52098cd7 b9078448
de8cc1ce
2: 879ecc29 ab6ba7a6 8ce891c6 480e4b99 7e6706e1 ff6e6a0e dcaba63d
fc9edea3
3: 908425f1 84a005e8 7c38c8dc aedc971a 793d9ccb b45d6855 90c0cbe4
f7c5fc85
4: 196cc0f8 f2543fbb ce043360 b44708a7 11d33b5d 2afceefd c19624e7
1e3f8acb
5: c75dd0bc 092c3c39 07e0c4ee ebcb956e 1f98b248 832c627f b7f3d6c1
a9ab89a3
6: 4bc49b87 6b8381f3 0ec423f9 9899ee0b 8f00f392 6ac9d34b 0b97895e
c1fe1ef4
==========================================================================
O: f8d4ac34 0ca50501 c68bd3c4 cc8bf657 69f2041b 0e1baf8c 48e1b554
556affca
==========================================================================
6: 4bc49b87 6b8381f3 0ec423f9 9899ee0b 8f00f392 6ac9d34b 0b97895e
c1fe1ef4
5: c75dd0bc 092c3c39 07e0c4ee ebcb956e 1f98b248 832c627f b7f3d6c1
a9ab89a3
4: 196cc0f8 f2543fbb ce043360 b44708a7 11d33b5d 2afceefd c19624e7
1e3f8acb
3: 908425f1 84a005e8 7c38c8dc aedc971a 793d9ccb b45d6855 90c0cbe4
f7c5fc85
2: 879ecc29 ab6ba7a6 8ce891c6 480e4b99 7e6706e1 ff6e6a0e dcaba63d
fc9edea3
1: 7d3857c6 7d7d1934 e0127b4a 823e3731 405113f4 52098cd7 b9078448
de8cc1ce
0: 65bd74f0 d7330f40 e59b4633 eedf9344 7bbef6a5 01982c42 2933c4c6
d49ef06e
==========================================================================
C: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000


K: 61616161 61616161 61616161 61616161 61616161 61616161 61616161
61616161
==========================================================================
   25c4e067 e1f9d162 44b0c0a2 0cb43bad b94de660 d2f05bce 71bbc494
f8eea938
   491f39e5 7708ee6e 2a175f5b 715a8d77 4379d8b6 65b368e8 0e139e2d
9ee337a9
   8c933a7a cbfa25ee 5c7be4d2 552eccf7 484f8452 a150cfb9 b33ded8b
48a1b8c2
   c5db9d78 31d2b144 3067063b 984dedf4 0bb83d3f 1420892b 8d2de790
9d6540ff
   a6081097 f35f225c 3a8d0706 479876b3 b5e0b7d0 4f912c85 cb0487a2
a410df66
   8f54e630 fd30dfe4 59afd569 e120de5c 64a7b818 60cfb7f8 57d1847a
c170fdbf
  
=======================================================================
   3f439a7b 700e815e 9c1627d9 59675e52 740bf351 f0e101e1 1aace184
890cc83f
   05575f61 87f1d2d9 26072cff 135c957e e1f9443e ba39c003 11bbf303
c32eaa25
==========================================================================
I: 61616161 61616161 61616161 61616161 61616161 61616161 61616161
61616161
==========================================================================
0: 5e22fb1a 116fe03f fd7746b8 38063f33 156a9230 91806080 7bcd80e5
e86da95e
1: d0deb90e e8a42b00 11172351 dc61fea8 6cd63f88 e85f37c0 ac123b77
b3b3179d
2: b84af3af 8be4282d aedede05 5516a4ad c8705871 10024f54 2db978cd
39a1369e
3: c9aeb9ae 9b90e007 7200f9b8 22adaaef 8975f24f 98404260 47d8c7cd
2095b8ba
4: f7e54e21 1ebaec3b 1305fb82 a7c921e4 9014f607 347f8513 52f2ffbd
92586b5e
5: 46299338 20d5ef4c 74257551 93303fa2 fffed4a1 fcc84935 3f9e80a2
f81825fa
6: 11d3707a bfc010d8 43c4b2bf 098f852d 7c9c847d a5d4983a 42c5cec7
4abe9a91
==========================================================================
O: 14842f1b 3831c201 65c39e40 1ad31053 9d65c043 1fed5839 537e3dc4
899030b4
==========================================================================
6: 11d3707a bfc010d8 43c4b2bf 098f852d 7c9c847d a5d4983a 42c5cec7
4abe9a91
5: 46299338 20d5ef4c 74257551 93303fa2 fffed4a1 fcc84935 3f9e80a2
f81825fa
4: f7e54e21 1ebaec3b 1305fb82 a7c921e4 9014f607 347f8513 52f2ffbd
92586b5e
3: c9aeb9ae 9b90e007 7200f9b8 22adaaef 8975f24f 98404260 47d8c7cd
2095b8ba
2: b84af3af 8be4282d aedede05 5516a4ad c8705871 10024f54 2db978cd
39a1369e
1: d0deb90e e8a42b00 11172351 dc61fea8 6cd63f88 e85f37c0 ac123b77
b3b3179d
0: 5e22fb1a 116fe03f fd7746b8 38063f33 156a9230 91806080 7bcd80e5
e86da95e
==========================================================================
C: 61616161 61616161 61616161 61616161 61616161 61616161 61616161
61616161


K: 00010203 04050607 08090a0b 0c0d0e0f 10111213 14151617 18191a1b
1c1d1e1f
==========================================================================
   0c4daa11 2e75ba96 1f609e3a 7e00bbeb 8888f4d7 c171ffd3 49927b6f
279f5571
   5b3d0e32 2cfd00cf c5a401a3 de839fac 9ce09053 159bfb90 84a2b6a3
4983ee6b
   f9a763d4 6a381b92 a7a160a7 c3191a95 7f8ac7db 5b8e6a7d 424a5c42
f9234af8
   5b36112b 36f86f11 2abe643d 36ba3455 4cd30c7e 50c4231a f1d1b99e
c55ca6e1
   540383d5 67bba58f bbea3ae2 277c8df8 625aea9d 48f7ae58 aa059baa
d2010864
   a1fb35ae aa249493 fc986f59 285f39a0 aaae16c1 851807f9 af06f002
d371ce9c
  
=======================================================================
   c524f87d 2240b01e 4ae65669 7221f3c3 0f9b463c 80f80ae1 eca50497
1a405634
   f3717b9c 5e8b7620 4717a0f8 ac932073 d291b762 349a72d3 2dc011b1
bea7871d
==========================================================================
I: 0f1e2d3c 4b5a6978 8796a5b4 c3d2e1f0 00112233 44556677 8899aabb
ccddeeff
==========================================================================
0: ca3ad541 691ad966 cd70f3dd b1f31233 0f8a640f c4ad6c96 643cae2c
d69db8cb
1: 7801e0bc e78a4683 7d26cc67 ab6aa90e e7b9ee15 0463f50e 41f18561
3f7803ac
2: 849c025f fd0dfc71 34951f20 8674fdd2 e90adbc9 ae192192 bf967762
77fc9452
3: 03842d0e c11a95ca 10d5c3e0 ccb5b9f3 0bb197c0 fe69e915 7cf46359
361b38ff
4: d630c430 545e2da6 eff89a6d edd6f4cf 40ae088f e0b3ee67 4e80ea76
e9fd2230
5: 968ad2a6 11913412 89a87670 28fc4063 62fc46eb 923c82e9 832f03f8
5c33c951
6: 9e24305e cb9afff9 959b879d 574a3de9 c828fa15 625ce66c 65e43157
766d30e5
==========================================================================
O: 6d554bc2 951189d9 d28c2765 fbd91d9a 1ab94d77 56c694bf 482420e6
c8cab7f8
==========================================================================
6: 9e24305e cb9afff9 959b879d 574a3de9 c828fa15 625ce66c 65e43157
766d30e5
5: 968ad2a6 11913412 89a87670 28fc4063 62fc46eb 923c82e9 832f03f8
5c33c951
4: d630c430 545e2da6 eff89a6d edd6f4cf 40ae088f e0b3ee67 4e80ea76
e9fd2230
3: 03842d0e c11a95ca 10d5c3e0 ccb5b9f3 0bb197c0 fe69e915 7cf46359
361b38ff
2: 849c025f fd0dfc71 34951f20 8674fdd2 e90adbc9 ae192192 bf967762
77fc9452
1: 7801e0bc e78a4683 7d26cc67 ab6aa90e e7b9ee15 0463f50e 41f18561
3f7803ac
0: ca3ad541 691ad966 cd70f3dd b1f31233 0f8a640f c4ad6c96 643cae2c
d69db8cb
==========================================================================
C: 0f1e2d3c 4b5a6978 8796a5b4 c3d2e1f0 00112233 44556677 8899aabb
ccddeeff


K: deadbeef abbababe deadbeef abbababe deadbeef abbababe deadbeef
abbababe
==========================================================================
   929bc3b2 1701280d a87dd056 8bee6a23 36b789f8 6711812f aabdea1d
7069a603
   e340098f c8dda71e 96817252 1a0ca3db 6fc803a6 f2b445ff 61c0d82e
4fb33123
   f5240521 f5b917d9 dbd36d7e 3d981945 1095ec10 f3f0815f b0bc8320
3448a51d
   777970dd 6351f4a1 9dad70ec 1f20a7b8 c18dd1d0 8472ab64 04b06cb0
2ad5a1c1
   980c3e3d 9982ed14 9117b612 9a9d39c4 86c4eda6 cfebe3b4 a2b2211e
5bb9128d
   0ea2e11b d5bb6448 37c984fd 87c810a7 23e5b6eb a34cbf93 13ca53b0
ee7aaa89
  
=======================================================================
   0393e0e2 40fa63aa 258390e9 05af7eec 910347ab eb34a3bc e92f34bb
aaed2e83
   c569a1e0 c2fdd065 894c26f3 3763e27a 9ec793b2 66f506e6 86d1657e
38444f64
==========================================================================
I: deadbeef abbababe deadbeef abbababe deadbeef abbababe deadbeef
abbababe
==========================================================================
0: dd3e5e0d eb40d914 fb2e2e06 ae15c452 4faef944 408e1902 37828a54
0157943d
1: 5c6194d1 3ea1ebd4 29671a8f e5b49275 16b4408a bb0e6711 be0d467f
4e59c592
2: 839538d5 e9cd51f7 238f39a6 a9111e1d b9db23da 20756aa1 777b29c0
e7f4b75a
3: 181f47d0 3b64fcd7 10fb4dd9 32943ca8 05be3372 81f15c1f 2c1814e2
de447c5e
4: 4d80e519 ade55f2f f80a8113 69bd2b36 860287a9 68bc474a 0370da7e
074b9474
5: 86382f28 c35d1290 d7feb8f9 7fe6782a 5bb9aa46 fa9db6f0 e3084c7d
bb77d9e2
6: fb16b6e8 39af894d 16b2e363 f9ddf95a 6b0de239 912bcfa6 19d540a4
d8499ce7
==========================================================================
O: 3e7f1708 fb525928 9ffec590 cebe1b20 f5ca718b f7dec940 9f0425da
e00dd383
==========================================================================
6: fb16b6e8 39af894d 16b2e363 f9ddf95a 6b0de239 912bcfa6 19d540a4
d8499ce7
5: 86382f28 c35d1290 d7feb8f9 7fe6782a 5bb9aa46 fa9db6f0 e3084c7d
bb77d9e2
4: 4d80e519 ade55f2f f80a8113 69bd2b36 860287a9 68bc474a 0370da7e
074b9474
3: 181f47d0 3b64fcd7 10fb4dd9 32943ca8 05be3372 81f15c1f 2c1814e2
de447c5e
2: 839538d5 e9cd51f7 238f39a6 a9111e1d b9db23da 20756aa1 777b29c0
e7f4b75a
1: 5c6194d1 3ea1ebd4 29671a8f e5b49275 16b4408a bb0e6711 be0d467f
4e59c592
0: dd3e5e0d eb40d914 fb2e2e06 ae15c452 4faef944 408e1902 37828a54
0157943d
==========================================================================
C: deadbeef abbababe deadbeef abbababe deadbeef abbababe deadbeef
abbababe


Appendix B: C implementation

If you define USE_VECTOR_TEST, the execution is a little slower (far
from
being noticeable), but you can output the testvectors.

*/

#if 1
#define USE_VECTOR_TEST
#endif

/*---------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <netinet/in.h>

#ifdef __unix__
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/times.h>
#include <sys/resource.h>
#endif

/* unices tend not to care about ANSI C fopen() definition, and
** refuse fopen strings containing a 'b' for 'binary mode'.
*/
#ifdef __unix__
#define BINARY ""
#else
#define BINARY "b"
#endif

#include <stddef.h>
typedef int int32;
typedef unsigned uint32;
typedef unsigned char byte;

#if 0
#define M_Q ((sqrt(5) - 1.0) / 2.0)
#else
#define M_Q 1.6180339887498949
#endif

#define countof(v) (sizeof(v) / sizeof((v)[0]))

#define ROTL(x, u) (((x) << ((u)&31)) | ((x) >> (32-((u)&31))))
#define ROTR(x, u) (((x) >> ((u)&31)) | ((x) << (32-((u)&31))))
#define LOAD(p) ( \
        (((unsigned) (((const unsigned char*)(p))[0])) << 000) \
|       (((unsigned) (((const unsigned char*)(p))[1])) << 010) \
|       (((unsigned) (((const unsigned char*)(p))[2])) << 020) \
|       (((unsigned) (((const unsigned char*)(p))[3])) << 030) \
)
#define SAVE(p, v) do { \
        unsigned char *_p = (unsigned char*)(p); \
        uint32 _v = (uint32)(v); \
        _p[0] = (_v >> 000) & 0xff; \
        _p[1] = (_v >> 010) & 0xff; \
        _p[2] = (_v >> 020) & 0xff; \
        _p[3] = (_v >> 030) & 0xff; \
} while (0)

#ifdef USE_VECTOR_TEST
static void (*putround) (unsigned i,
        uint32 a, uint32 b, uint32 c, uint32 d,
        uint32 e, uint32 f, uint32 g, uint32 h);
#else
#define putround(i,a,b,c,d,e,f,g,h) (void)0
#endif


/*---------------------------------------------------------------------------*/

#define PW (((uint32) ((M_PI - 3.0) * UINT_MAX)) | 1)

#define VALCNT 8
#define BLKSIZ (VALCNT*4)
#define ROUNDS 6
#define KEYCNT (VALCNT * ROUNDS)

struct keysched_s {
        uint32 t[KEYCNT];
        uint32 w[VALCNT*2];
};
typedef struct keysched_s keysched;

void set_key (keysched *key, const void* s, size_t x)
{
        size_t i;
        unsigned char *p = (unsigned char *)s;
        uint32 l[64];
        
        /* initialize l */
        for (i = 0; i != countof(l); ++i)
                l[i] = 0;
        if (x > countof(l)*4)
                x = countof(l)*4;
        for (i = 0; i != x; ++i)
                l[i/4] |= (p[i] << (010 * (3-(i%4))));

        /* avalanche addition */
        for (i = 0; i != 3*countof(key->t); ++i) {
                l[i % countof(l)] += PW
                        + l[(i+3) % countof(l)]
                        + ROTL (l[(i+11) % countof(l)], 3)
                        + ROTL (l[(i+31) % countof(l)], 15)
                        + ROTL (l[(i+53) % countof(l)], 13)
                        + ROTL (l[(i+57) % countof(l)], 7)
                        + ROTL (l[(i+62) % countof(l)], 1);
        }

        /* copy results */
        for (i = 0; i != countof(key->t); ++i) {
                key->t[i] = l[i];
        }
        for (i = 0; i != countof(key->w); ++i) {
                key->w[i] = l[48+i];
        }
        (void) memset (l, 0, sizeof(l)); /* zap memory */
}

static const uint32 brt1_v[3] = {
        0xffffffff,
        0x55555555,
        0x00000000
};
static const uint32 brt2_v[5] = {
        0xffffffff,
        0x77777777,
        0x33333333,
        0x11111111,
        0x00000000
};
static const uint32 brt3_v[9] = {
        0xffffffff,
        0x7f7f7f7f,
        0x3f3f3f3f,
        0x1f1f1f1f,
        0x0f0f0f0f,
        0x07070707,
        0x03030303,
        0x01010101,
        0x00000000
};
static const uint32 brt4_v[17] = {
        0xffffffff,
        0x7fff7fff,
        0x3fff3fff,
        0x1fff1fff,
        0x0fff0fff,
        0x07ff07ff,
        0x03ff03ff,
        0x01ff01ff,
        0x00ff00ff,
        0x007f007f,
        0x003f003f,
        0x001f001f,
        0x000f000f,
        0x00070007,
        0x00030003,
        0x00010001,
        0x00000000
};

#define BRTL(x, u, v) ( \
        (((x) & (v)[(u) & (countof(v)-2)]) << ((u) & (countof(v)-2))) \
        | (((x) >> ((countof(v)-1) - ((u) & (countof(v)-2)))) \
                & (v)[(countof(v)-1) - ((u) & (countof(v)-2))]))
#define BRTR(x, u, v) ( \
        (((x) >> ((u) & (countof(v)-2))) & (v)[((u) & (countof(v)-2))]) \
        | (((x) & (v)[(countof(v)-1) - ((u) & (countof(v)-2))]) \
                << ((countof(v)-1) - ((u) & (countof(v)-2)))))

#define BRTL1(x, u) BRTL(x, u, brt1_v)
#define BRTR1(x, u) BRTR(x, u, brt1_v)
#define BRTL2(x, u) BRTL(x, u, brt2_v)
#define BRTR2(x, u) BRTR(x, u, brt2_v)
#define BRTL3(x, u) BRTL(x, u, brt3_v)
#define BRTR3(x, u) BRTR(x, u, brt3_v)
#define BRTL4(x, u) BRTL(x, u, brt4_v)
#define BRTR4(x, u) BRTR(x, u, brt4_v)

void encrypt_block (const keysched *k, const void* iblock, void* oblock)
{
        register uint32 u;
        uint32 a, b, c, d, e, f, g, h;
        unsigned i, j;
        unsigned char *ip = (unsigned char*)iblock;
        unsigned char *op = (unsigned char*)oblock;

        a = LOAD(ip+0x00); b = LOAD(ip+0x04); c = LOAD(ip+0x08); d =
LOAD(ip+0x0c);
        e = LOAD(ip+0x10); f = LOAD(ip+0x14); g = LOAD(ip+0x18); h =
LOAD(ip+0x1c);
        a ^= k->w[0x0]; b ^= k->w[0x1]; c ^= k->w[0x2]; d ^= k->w[0x3];
        e ^= k->w[0x4]; f ^= k->w[0x5]; g ^= k->w[0x6]; h ^= k->w[0x7];

        i = 0; j = KEYCNT;
        do {
#ifdef USE_VECTOR_TEST
                if ((i & 7) == 0) putround (i/8, a, b, c, d, e, f, g, h);
#endif
                --j;
                u = k->t[j] + h;
                a += PW;
                a += b;                     a = BRTL3(a, u>>26);
                a ^= c; a = ROTL(a, u>>10); a = BRTL4(a, u>>19);
                a += d;                     a = BRTL2(a, u>>29);
                a ^= e; a = ROTL(a, u>>5);  a = BRTL3(a, u>>23);
                a += f;                     a = BRTL4(a, u>>15);
                a ^= g; a = ROTL(a, u);     a = BRTL1(a, u>>31);
                a += k->t[i];
                ++i;
                u = a; a = b; b = c; c = d; d = e; e = f; f = g; g = h; h = u;
        } while (j != 0);
        putround (i/8, a, b, c, d, e, f, g, h);

        a ^= k->w[0x8]; b ^= k->w[0x9]; c ^= k->w[0xa]; d ^= k->w[0xb];
        e ^= k->w[0xc]; f ^= k->w[0xd]; g ^= k->w[0xe]; h ^= k->w[0xf];
        SAVE(op+0x00, a); SAVE(op+0x04, b); SAVE(op+0x08, c); SAVE(op+0x0c, d);
        SAVE(op+0x10, e); SAVE(op+0x14, f); SAVE(op+0x18, g); SAVE(op+0x1c, h);
}

void decrypt_block (const keysched *k, const void* iblock, void* oblock)
{
        register uint32 u;
        uint32 a, b, c, d, e, f, g, h;
        unsigned i, j;
        unsigned char *ip = (unsigned char*)iblock;
        unsigned char *op = (unsigned char*)oblock;

        a = LOAD(ip+0x00); b = LOAD(ip+0x04); c = LOAD(ip+0x08); d =
LOAD(ip+0x0c);
        e = LOAD(ip+0x10); f = LOAD(ip+0x14); g = LOAD(ip+0x18); h =
LOAD(ip+0x1c);
        a ^= k->w[0x8]; b ^= k->w[0x9]; c ^= k->w[0xa]; d ^= k->w[0xb];
        e ^= k->w[0xc]; f ^= k->w[0xd]; g ^= k->w[0xe]; h ^= k->w[0xf];

        i = KEYCNT; j = 0;
        do {
#ifdef USE_VECTOR_TEST
                if ((i & 7) == 0) putround (i/8, a, b, c, d, e, f, g, h);
#endif
                u = h; h = g; g = f; f = e; e = d; d = c; c = b; b = a; a = u;
                --i;
                u = k->t[j] + h;
                a -= k->t[i];
                a = BRTR1(a, u>>31); a = ROTR(a, u);     a ^= g;
                a = BRTR4(a, u>>15);                     a -= f;
                a = BRTR3(a, u>>23); a = ROTR(a, u>>5);  a ^= e;
                a = BRTR2(a, u>>29);                     a -= d;
                a = BRTR4(a, u>>19); a = ROTR(a, u>>10); a ^= c;
                a = BRTR3(a, u>>26);                     a -= b;
                a -= PW;
                ++j;
        } while (i != 0);
        putround (i/8, a, b, c, d, e, f, g, h);

        a ^= k->w[0x0]; b ^= k->w[0x1]; c ^= k->w[0x2]; d ^= k->w[0x3];
        e ^= k->w[0x4]; f ^= k->w[0x5]; g ^= k->w[0x6]; h ^= k->w[0x7];
        SAVE(op+0x00, a); SAVE(op+0x04, b); SAVE(op+0x08, c); SAVE(op+0x0c, d);
        SAVE(op+0x10, e); SAVE(op+0x14, f); SAVE(op+0x18, g); SAVE(op+0x1c, h);
}

/*---------------------------------------------------------------------------*/

static unsigned randidx;
static uint32 randpool[64];

static void mixrand ()
{
        unsigned i;
        uint32 *k = randpool;

        for (i = 0; i != 3*countof(randpool); ++i) {
                k[i % countof(randpool)]
                        += k[(i+3) % countof(randpool)]
                        + (((uint32) ((M_PI - 3.0) * UINT_MAX)) | 1)
                        + ROTL (k[(i+11) % countof(randpool)], 7)
                        + ROTL (k[(i+31) % countof(randpool)], 15)
                        + ROTL (k[(i+51) % countof(randpool)], 19)
                        + ROTL (k[(i+55) % countof(randpool)], 3)
                        + ROTL (k[(i+62) % countof(randpool)], 1);
        }
}

static void initrand ()
{
        unsigned i;
        uint32 *k = randpool;

        randidx = 0;
        k[0] += (((uint32)((M_E - 2.0) * UINT_MAX)) | 1);
        for (i = 1; i != countof(randpool); ++i)
                k[i] += k[i-1] + (((uint32) ((M_Q - 1.0) * UINT_MAX)) | 1);
}

static void addrand (uint32 x)
{
        randpool[randidx] += (x + randidx);
        ++randidx;
        if (randidx == countof(randpool)) {
                mixrand ();
                randidx = 0;
        }
}

static void addrandbytes (const void *p, size_t x)
{
        size_t i;
        uint32 v;
        unsigned char *s = (unsigned char*) p;

        v = 0;
        for (i = 0; i != x; ++i) {
                v |= (uint32)(s[i]) << (010 * (3 - (i&3)));
                if ((i&3) == 3) {
                        addrand (v);
                        v = 0;
                }
        }
        if (! (i&3)) {
                addrand (v);
        }
}

static void endrand ()
{
        if (randidx)
                mixrand ();
}

#ifdef __unix__
extern char **environ;
#endif

void geniv (void* d, size_t x)
{
        size_t i;
        char buf[1024];
        static const char compiled[] =
                __FILE__ " " __DATE__ " " __TIME__;
        void *p;
        jmp_buf frame;
        FILE *f;
#ifdef __unix__
        struct rusage usage;
        struct tms tmbuf;
        struct timeval tmvbuf;
        struct timezone tmzbuf;
#endif

        initrand ();

        addrand (time (NULL));
        addrand (rand ());        /* hoping someone else already used it */
        addrandbytes (buf, sizeof(buf)); /* loading some uninitalized data */
        i = 0xdeadbeef;
        addrandbytes (&i, sizeof(i)); /* make it depend on endian */

#ifdef __unix__
        addrand (getpid ());
        addrand (getppid ());
        addrand (getpgrp ());
        addrand (getuid ());
        addrand (geteuid ());
        addrand (getgid ());
        addrand (getegid ());
        addrand (gethostid ());
        getrusage (RUSAGE_SELF, &usage);
        addrandbytes (&usage, sizeof(usage));
        for (i = 0; environ[i] == NULL; ++i) {
                addrandbytes (environ[i], strlen(environ[i]));
        }
        i = times (&tmbuf);
        addrand (i);
        addrandbytes (&tmbuf, sizeof(tmbuf));
        gettimeofday (&tmvbuf, &tmzbuf);
        addrandbytes (&tmvbuf, sizeof(tmvbuf));
        addrandbytes (&tmzbuf, sizeof(tmzbuf));
        if (getcwd (buf, sizeof(buf))) {
                addrandbytes (buf, strlen (buf));
        }

#ifdef __linux__
        /*
        ** OpenBSD (and very likely the other *BSD as well) also offer
        ** random devices. I only don't have one at hand to test it.
        */
        if ((f = fopen ("/dev/urandom", "r" BINARY))) {
                /* "/dev/random" offers more security, but might block */
                i = fread (d, 1, x, f);
                fclose (f);
                if (i > 0) addrandbytes (d, i);
        }
#endif
#endif

        addrand (clock ());
        addrandbytes (compiled, strlen(compiled));
        setjmp (frame);
        addrandbytes (&frame, sizeof(frame));
        addrand ((uint32) (unsigned long) (void*) (buf));
        addrand ((uint32) (unsigned long) (void*) compiled);
        p = malloc (16);
        if (p) {
                addrand ((uint32) (unsigned long) (void*) p);
                addrandbytes (p, 16);
                free (p);
        }
        addrand ((uint32) (unsigned long) (void*) &geniv);
        addrand ((uint32) (unsigned long) (void*) &fprintf);

        endrand ();
        if (x > sizeof(randpool))
                x = sizeof(randpool); /* sorry */
        memcpy (d, randpool, x);
}

/*---------------------------------------------------------------------------*/

#ifdef USE_MULTIBLOCK
/*
** IMHO completely superflous - who needs EBC mode ?!? But added
** according to the requirements of the cipher contest.
*/

void ebc_encrypt (const keysched* k, const void *input,
        void *output, size_t len)
{
        size_t x;

        for (x = 0; x < len; x += BLKSIZ) {
                encrypt_block (k, (const char*)input + x, (char*)output + x);
        }
}

void ebc_decrypt (const keysched* k, const void *input,
        void *output, size_t len)
{
        size_t x;

        for (x = 0; x < len; x += BLKSIZ) {
                decrypt_block (k, (const char*)input + x, (char*)output + x);
        }
}
#endif

#define MAGIC1  0x73cfbbaf /* valid header */
#define MAGIC2  0x73fbcbbf /* header without length info */

static int cbc_file_encrypt (const keysched *k, FILE *ifile, FILE
*ofile)
{
        int warn, flag;
        size_t i;
        long fpos;
        uint32 last;
        uint32 iv[BLKSIZ / sizeof(uint32)];
        uint32 bf[BLKSIZ / sizeof(uint32)];

        warn = 0;
        memset (iv, 0, sizeof(iv));
        flag = fseek (ifile, 0, SEEK_END);
        if (flag == -1) {
                iv[0] = htonl(MAGIC2);
                iv[1] = 0;
        } else {
                if (fgetpos (ifile, &fpos) == -1)
                        return -1;
                last = fpos & (BLKSIZ-1);
                iv[0] = htonl(MAGIC1);
                iv[1] = htonl(last);
                if (fseek (ifile, 0, SEEK_SET) == -1)
                        return -1;
        }
        fwrite (iv, sizeof(iv), 1, ofile);
        geniv (iv, BLKSIZ);
        fwrite (iv, sizeof(iv), 1, ofile);

        while ((i = fread (bf, 1, sizeof(bf), ifile)) > 0) {
                memset (bf + i, 0, sizeof(bf)-i);
                last = i;
                for (i = 0; i != countof(iv); ++i) {
                        bf[i] ^= iv[i];
                }
                encrypt_block (k, bf, iv);
                fwrite (iv, sizeof(iv), 1, ofile);
        }
        if (flag == -1 && fseek (ofile, 0, SEEK_SET) != -1) {
                memset (iv, 0, sizeof(iv));
                iv[0] = htonl(MAGIC1);
                iv[1] = htonl(last);
                fwrite (iv, sizeof(iv), 1, ofile);
                fseek (ofile, 0, SEEK_END);
        } else if (flag == -1)
                warn = 1;
        return warn;
}

static int cbc_file_decrypt (const keysched *k, FILE *ifile, FILE
*ofile)
{
        int warn, flag;
        size_t i;
        uint32 last;
        unsigned iv[BLKSIZ / sizeof(unsigned)];
        unsigned bf[BLKSIZ / sizeof(unsigned)];
        unsigned tm[BLKSIZ / sizeof(unsigned)];

        if (fread (iv, sizeof(iv), 1, ifile) != 1)
                return -1;
        warn = 0;
        if (ntohl(iv[0]) == MAGIC2) {
                warn = 1;
                last = BLKSIZ;
        } else if (ntohl(iv[0]) == MAGIC1) {
                last = ntohl (iv[1]) & (BLKSIZ-1);
                if (! last) last = BLKSIZ;
        } else
                return -1;
        if (fread (iv, sizeof(iv), 1, ifile) != 1)
                return -1;
        
        for (flag = 0; fread (bf, sizeof(bf), 1, ifile) == 1;) {
                if (flag) {
                        fwrite (tm, sizeof(tm), 1, ofile);
                }
                flag = 1;
                decrypt_block (k, bf, tm);
                for (i = 0; i != countof(iv); ++i) {
                        tm[i] ^= iv[i];
                }
                for (i = 0; i != countof(iv); ++i) {
                        iv[i] = bf[i];
                }
        }
        if (flag) {
                fwrite (tm, 1, last, ofile);
        }
        return warn;
}

#ifdef USE_VECTOR_TEST
static void putbuf (const char *s, const char *v)
{
        int i;
        unsigned char c;
        static const char hex[16] = {'0','1','2','3','4',
                '5','6','7','8','9','a','b','c','d','e','f'};

        for (i = 0; s[i] != 0; ++i)
                putc (s[i], stdout);
        for (i = 0; i != BLKSIZ; ++i) {
                if (i && ((i&3) == 0)) putc (' ', stdout);
                c = (unsigned char) v[i];
                putc (hex[(c >> 4) & 0xf], stdout);
                putc (hex[(c >> 0) & 0xf], stdout);
        }
        putc ('\n', stdout);
}


static void dont_putround (unsigned i,
        uint32 a, uint32 b, uint32 c, uint32 d,
        uint32 e, uint32 f, uint32 g, uint32 h)
{
        return;
}

static void (*putround) (unsigned i,
        uint32 a, uint32 b, uint32 c, uint32 d,
        uint32 e, uint32 f, uint32 g, uint32 h) = dont_putround;

static void do_putround (unsigned i,
        uint32 a, uint32 b, uint32 c, uint32 d,
        uint32 e, uint32 f, uint32 g, uint32 h)
{
        char title[20];
        unsigned char line[0x20];

        sprintf (title, "%x: ", i);
        SAVE (line+0x00, a);
        SAVE (line+0x04, b);
        SAVE (line+0x08, c);
        SAVE (line+0x0c, d);
        SAVE (line+0x10, e);
        SAVE (line+0x14, f);
        SAVE (line+0x18, g);
        SAVE (line+0x1c, h);
        putbuf (title, line);
}

static void putsched (const keysched *K)
{
        int i;
        unsigned char *p = (unsigned char*) (void*) K;
        static const char delim[] =
                "   ----------------------------------"
                "-------------------------------------\n";
        for (i = 0; i < sizeof(*K); i += BLKSIZ) {
                if (i == 6*BLKSIZ) fputs (delim, stdout);
                putbuf ("   ", p + i);
        }
}

struct test {
        char key[32];
        char ibf[32];
};

static const struct test testv[] = {
        { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} },
        { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} },
        { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1} },
        { {0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} },
        { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} },
        { {'a','a','a','a','a','a','a','a',
                'a','a','a','a','a','a','a','a',
                'a','a','a','a','a','a','a','a',
                'a','a','a','a','a','a','a','a'},
                {'a','a','a','a','a','a','a','a',
                        'a','a','a','a','a','a','a','a',
                        'a','a','a','a','a','a','a','a',
                        'a','a','a','a','a','a','a','a'} },
        { {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
                16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31},
                {0x0f,0x1e,0x2d,0x3c,0x4b,0x5a,0x69,0x78,
                        0x87,0x96,0xa5,0xb4,0xc3,0xd2,0xe1,0xf0,
                        0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
                        0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff} },
        { {0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe,
                0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe,
                0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe,
                0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe},
                {0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe,
                        0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe,
                        0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe,
                        0xde,0xad,0xbe,0xef,0xab,0xba,0xba,0xbe} }
};

static void do_vector_test ()
{
        int i;
        char buf[BLKSIZ], bf2[BLKSIZ];
        keysched K;
        static const char lnsep[] =
                "-------------------------------------"
                "-------------------------------------\n";
        const char * const lnsep2 = lnsep + 0;

        putround = do_putround;

        /*-----------------------------------------------------*/
        for (i = 0; i != countof(testv); ++i) {
                putc ('\n', stdout);
                set_key (&K, testv[i].key, 32);
                putbuf ("K: ", testv[i].key);
                printf (lnsep);
                putsched (&K);
                printf (lnsep);
                putbuf ("I: ", testv[i].ibf);
                printf (lnsep2);
                encrypt_block (&K, testv[i].ibf, buf);
                printf (lnsep2);
                putbuf ("O: ", buf);
                printf (lnsep2);
                decrypt_block (&K, buf, bf2);
                printf (lnsep2);
                putbuf ("C: ", bf2);
                if (memcmp (testv[i].ibf, bf2, 32) != 0)
                        printf (
                                "*****************************"
                                " INVALID RESULT "
                                "*****************************\n"
                        );
                putc ('\n', stdout);
        }
}
#endif


#define KEYSETUP_COUNT 1000000
#define ENCRYPT_COUNT  1000000

static void do_profile_test ()
{
        int i;
        char buf[BLKSIZ];
        static const char key[32] = {
                '\x00','\x01','\x02','\x03','\x04','\x05','\x06','\x07',
                '\x08','\x09','\x0a','\x0b','\x0c','\x0d','\x0e','\x0f',
                '\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17',
                '\x18','\x19','\x1a','\x1b','\x1c','\x1d','\x1e','\x1f'
        };
        static const char plain[BLKSIZ] = {
                '\x00','\x01','\x02','\x03','\x04','\x05','\x06','\x07',
                '\x08','\x09','\x0a','\x0b','\x0c','\x0d','\x0e','\x0f',
                '\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17',
                '\x18','\x19','\x1a','\x1b','\x1c','\x1d','\x1e','\x1f'
        };
        keysched K;
        clock_t t;

        /*-----------------------------------------------------*/
        printf ("%d times key schedule (%d bits): ",
                KEYSETUP_COUNT, sizeof(key)*8);
        fflush (stdout);
        t = clock ();
        for (i = 0; i != KEYSETUP_COUNT; ++i) {
                set_key (&K, key, sizeof(key));
        }
        t = clock () - t;
        printf ("%0.14g sec\n", (double)t / CLOCKS_PER_SEC);
        
        /*-----------------------------------------------------*/
        printf ("%d times encrypt (a %d byte): ",
                ENCRYPT_COUNT, BLKSIZ);
        fflush (stdout);
        t = clock ();
        for (i = 0; i != ENCRYPT_COUNT; ++i) {
                encrypt_block (&K, plain, buf);
        }
        t = clock () - t;
        printf ("%0.14g sec\n", (double)t / CLOCKS_PER_SEC);
}

/*---------------------------------------------------------------------------*/
static void usage () {
        printf (
"Usage: paranoia (-e|-d) (-p|-K\"key\"|keyfile) input output\n"
"   Or: paranoia (--help|--version|"
#ifdef USE_VECTOR_TEST
"--vectors|"
#endif
                "--profile)\n"
        );
}

int main (int argc, char *argv[])
{
        int flag;
        char key[2048];
        keysched k;
        FILE *ifile, *ofile;

        if (argc == 2) {
                if (strcmp (argv[1], "--help") == 0) {
                        usage ();
                        exit (0);
                } else if (strcmp (argv[1], "--version") == 0) {
                        printf (
                "Paranoia file cipher V1.0.1 [Jun 27 2000]\n"
                "Copyright (c) 2000 Runu Knips, Siegen, Germany.\n"
                "  This is free software, no warranty for anything,\n"
                "  especially also no warranty for data losses or\n"
                "  weak security, therefore use at own risk.\n"
                "Compiled: " __DATE__ " at " __TIME__ "\n"
                        );
                        exit (0);
#ifdef USE_VECTOR_TEST
                } else if (strcmp (argv[1], "--vectors") == 0) {
                        do_vector_test ();
                        exit (0);
#endif
                } else if (strcmp (argv[1], "--profile") == 0) {
                        do_profile_test ();
                        exit (0);
                }
        }
        if (argc != 5) {
                usage ();
                exit (1);
        }
        if (
                strcmp (argv[1], "-e") == 0
                || strcmp (argv[1], "--encrypt") == 0
        ) {
                flag = 1;
        } else if (
                strcmp (argv[1], "-d") == 0
                || strcmp (argv[1], "--decrypt") == 0
        ) {
                flag = 0;
        } else {
                usage ();
                exit (1);
        }

        if (argv[2][0] != '-') {
                ifile = fopen (argv[2], "r" BINARY);
                if (! ifile) {
                        fprintf (stderr, "can't open key file %s\n", argv[2]);
                        exit (1);
                }
                memset (key, 0, sizeof(key));
                fread (key, sizeof(key), 1, ifile);
                fclose (ifile);
        } else if (
                strcmp (argv[2], "-p") == 0
                || strcmp (argv[2], "--prompt") == 0
        ) {
                int i, ch;

                printf ("Password: ");
                fflush (stdout);
                for (i = 0; (ch = getc (stdin)) != '\n' && ch != EOF;) {
                        if (ch == '\b') {
                                if (i > 0) --i;
                        } else {
                                if (i < sizeof(key)) key[i] = ch;
                                ++i;
                        }
                }
                if (i < sizeof(key)) {
                        memset (key + i, 0, sizeof(key) - i);
                }
        } else if (argv[2][1] == 'K') {
                /* that is the first time that strncpy's braindamaged
                ** definition is exactly the right thing I need !
                */
                strncpy (key, argv[2]+2, sizeof(key));
        } else {
                fprintf (stderr,
"Bad format of key argument (either -p, -K<pass>, or filename
expected).\n");
                exit (EXIT_FAILURE);
        }

        ifile = fopen (argv[3], "r" BINARY);
        if (! ifile) {
                fprintf (stderr, "can't open input file %s\n", argv[3]);
                exit (1);
        }
        
        ofile = fopen (argv[4], "w" BINARY);
        if (! ifile) {
                fprintf (stderr, "can't open output file %s\n", argv[4]);
                exit (1);
        }

        set_key (&k, key, sizeof(key));

        (void) memset (key, 0, sizeof(key)); /* zap memory */

        if (flag) {
                flag = cbc_file_encrypt (&k, ifile, ofile);
                if (flag > 0) {
                        fprintf (stderr,
"Warning: couldn't set exact file length (will align to block
size).\n");
                }
        } else {
                flag = cbc_file_decrypt (&k, ifile, ofile);
                if (flag > 0) {
                        fprintf (stderr,
"Warning: unknown block offset of end (tailing zeros possible).\n");
                }
        }

        (void) memset (&k, 0, sizeof(k)); /* zap memory */

        (void) fclose (ifile);
        (void) fclose (ofile);
        
        if (flag < 0) {
                fprintf (stderr, "Error during encryption, aborted.\n");
                (void) remove (argv[4]);
                return EXIT_FAILURE;
        } else {
                return EXIT_SUCCESS;
        }
}

/*---------------------------------------------------------------------------*/

------------------------------


** FOR YOUR REFERENCE **

The service address, to which questions about the list itself and requests
to be added to or deleted from it should be directed, is:

    Internet: [EMAIL PROTECTED]

You can send mail to the entire list (and sci.crypt) via:

    Internet: [EMAIL PROTECTED]

End of Cryptography-Digest Digest
******************************

Reply via email to