3.2. *_init function
The *_init function generally takes a pointer to the key as first parameter.
For ciphers where the keysize is not fixed the second parameter gives the
- keysize (in bits regularly) and the last parameter points to a context variable
- to fill.
+ keysize (in bits regularly) and the last parameter points to the context
+ variable to fill.
For some ciphers there are additonal parameters like the number of rounds,
these parameters generally occur before the context pointer.
--- /dev/null
+====================================
+= Usage of streamciphers =
+====================================
+
+Author: Daniel Otte
+email: daniel.otte@rub.de
+
+
+0. Foreword
+ This file will describe how to use the streramcipher implementations provided
+ by this library. It will not only show how to call the cryptographic functions
+ but also discuss a little how to build security mechanisms from that.
+
+1. What a streamcipher does
+ A streamcipher normaly generates a deterministic, random looking stream of
+ bits, known as keystream. For encryption purpose this keystream is XORed with
+ the data stream. So decryption is exactly the same as encryption. The
+ datastream is XORed with the keystream giving the plaintext. So both sides need
+ exactly the same streamcipher in the same state.
+
+1.1. high frequent parameters:
+ outputsize: 8 bit, 1 bit
+ keysize: 64 bit, 80 bit, 128 bit
+ IVsize: 64 bit
+
+2. Parts of a streamcipher
+ * generation algorithm
+ * initialisation algorithm
+ * state
+ As we can see all streamciphers seem to utilize an internal state which
+ determines the output. This state is initialized by the initialisation
+ algorithm with a key and an IV (initialisation vector). It is very important
+ for security that _never_ the same key with the same IV is used again. The
+ IV is not required to be kept secret.
+
+3. streamcipher API
+ The API is not always consistent due to the fact that we tried to optimize the
+ code for size (flash, heap and stack) and speed (runtime of the different
+ components).
+ Generally the API of the implemented streamciphers consists of:
+
+ *_init function, which implements the initialisation
+ *_gen function, which implements the streamcipher algorithm and generates a
+ keystream output
+ *_ctx_t context type, which contains internal state information
+
+3.1 look at the prototypes
+ Generally the prototypes (defined in the *.h files) will tell you what
+ parameter means what.
+
+3.1.2 sizes in bits and bytes
+ Working with cryptographical functions involves working with different lengths.
+ Some times you want to know it in bits and sometimes in bytes. To reduce
+ frustration and to avoid bugs we suffix a length parameter with either _b or _B
+ depending on the meaning. _b means in bits and _B means in bytes
+ (big b big word).
+
+3.2. *_init function
+ The *_init function generally takes a pointer to the key as first parameter.
+ For ciphers where the keysize is not fixed the second parameter gives the
+ keysize (in bits regularly) followed by a pointer to the IV and a length
+ parameter for not fixed IV sizes (both are omitted if the algorithm does not
+ specify IV handling, in this case a part of the key should be used as IV).
+ The last parameter points to the context variable to fill.
+
+3.3. *_gen function
+ The *_gen function updates the internal state to which a pointer is given as
+ parameter and returns a fixed length part of the keystream as return value.
+
+
+
\ No newline at end of file
*
*/
+#include <avr/io.h>
+
+
+.macro push_ p1:req, p2:vararg
+ push \p1
+.ifnb \p2
+ push_ \p2
+.endif
+.endm
+
+.macro pop_ p1:req, p2:vararg
+ pop \p1
+.ifnb \p2
+ pop_ \p2
+.endif
+.endm
+
+.macro push_range from:req, to:req
+ push \from
+.if \to-\from
+ push_range "(\from+1)",\to
+.endif
+.endm
+
+.macro pop_range from:req, to:req
+ pop \to
+.if \to-\from
+ pop_range \from,"(\to-1)"
+.endif
+.endm
+
+.macro stack_alloc size:req, reg1=r30, reg2=r31
+ in \reg1, _SFR_IO_ADDR(SPL)
+ in \reg2, _SFR_IO_ADDR(SPH)
+ sbiw r30, \size
+ out _SFR_IO_ADDR(SPH), \reg2
+ out _SFR_IO_ADDR(SPL), \reg1
+.endm
+
+.macro stack_free size:req, reg1=r30, reg2=r31
+ in \reg1, _SFR_IO_ADDR(SPL)
+ in \reg2, _SFR_IO_ADDR(SPH)
+ adiw r30, \size
+ out _SFR_IO_ADDR(SPH), \reg2
+ out _SFR_IO_ADDR(SPL), \reg1
+.endm
+
/* +---+---+---------------------+
* | i | j | ......<256>........ |
* +---+---+---------------------+
*/
.global arcfour_init
-
-;== arcfour_init ==
-; this function initialises the context
-; param1: 16-bit pointer to a ctx struct
-; given in r25,r24
-; param2: 16-bit pointer to a key
-; given in r23,r22
-; param1: 8-bit integer indicating keylength in byte
-; given in r20
-
+/*
+ *== arcfour_init ==
+ * this function initialises the context
+ * param1: 16-bit pointer to the key
+ * given in r24:r25
+ * param2: 8-bit integer indicating keylength in byte
+ * given in r22
+ * param3: 16-bit pointer to a ctx struct
+ * given in r20:r21
+ */
arcfour_init:
- push r29
- push r28
- push r2
-
- movw r26, r24 /* X points to ctx */
- movw r30, r22 /* Z points to key */
+ push_ r2, r28, r29
+ movw r26, r20 /* X points to ctx */
+ movw r30, r24 /* Z points to key */
st X+, r1
- st X+, r1 /* X points to S */
+ st X+, r1 /* X points to S */
+ movw r20, r26 /* store pointer to S in r21:r20 */
1:
st X+, r1
inc r1
brne 1b
- adiw r24, 2 /* r24:r25 points to S */
- clr r21 /* r21 is j */
- mov r18, r20 /* r18 is keyindex counter */
+ movw r26, r20
+ clr r18 /* r18 is keyindex counter */
clr r0
+ clr r19
2:
- movw r26, r24
- ld r19, Z+
- add r21, r19 /* j+= key[i%length] */
-
- add r26, r1
- adc r27, r0
- ld r19, X
- add r21, r19 /* j += S[i] */
-
- dec r18 /* check the key-index counter */
- brne 3f
- movw r30, r22
- mov r18, r20
-3: /* now swap(S[i], S[j]) */ /* r19 is still S[i] */
- movw r28, r24
- add r28, r21
- adc r29, r0 /* Y points to S[j]*/
+ ld r23, X
+ ld r2, Z+
+ add r19, r2
+ add r19, r23
+ movw r28, r20 /* load pointer to S in Y */
+ add r28, r19
+ adc r29, r1
ld r2, Y
- st Y, r19
- st X, r2
- inc r1
+ st Y, r23
+ st X+, r2
+ inc r18
+ cp r18, r22
+ brne 3f
+ movw r30, r24
+ clr r18
+3:
+ inc r0
brne 2b
-
- pop r2
- pop r28
- pop r29
+ pop_ r29, r28, r2
ret
/*
* length is length of key in bytes!
*/
-void arcfour_init(arcfour_ctx_t *ctx, void *key, uint8_t length_B){
+void arcfour_init(const void *key, uint8_t length_B, arcfour_ctx_t *ctx){
uint8_t t;
- unsigned x,y=0;
+ uint16_t x,y=0;
for(x=0; x<= 255; ++x)
ctx->s[x]=x;
for(x=0; x<= 255; ++x){
y += ctx->s[x] + ((uint8_t*)key)[x % length_B];
y &= 0xff;
+ /* ctx->s[y] <--> ctx->s[x] */
t = ctx->s[y];
ctx->s[y] = ctx->s[x];
ctx->s[x] = t;
* \param length_B length of the key in bytes (between 1 and 255)
*/
-void arcfour_init(arcfour_ctx_t *ctx, void *key, uint8_t length_B);
+void arcfour_init(const void *key, uint8_t length_B, arcfour_ctx_t *ctx);
/** \fn uint8_t arcfour_gen(arcfour_ctx_t *ctx)
* \brief generates a byte of keystream
* additional validation-functions *
*****************************************************************************/
void arcfour_genctx_dummy(uint8_t* key, uint16_t keysize, void* ctx){
- arcfour_init(ctx, key, (keysize+7)/8);
+ arcfour_init(key, (uint8_t)((keysize+7)/8), ctx);
}
nessie_stream_run();
}
+void testrun_performance_arcfour(void){
+ nessie_stream_ctx.outsize_b = 8; /* actually unused */
+ nessie_stream_ctx.keysize_b = 128; /* this is theone we have refrence vectors for */
+ nessie_stream_ctx.ivsize_b = (uint16_t)-1;
+ nessie_stream_ctx.name = cipher_name;
+ nessie_stream_ctx.ctx_size_B = sizeof(arcfour_ctx_t);
+ nessie_stream_ctx.cipher_genctx = (nessie_stream_genctx_fpt)arcfour_genctx_dummy;
+ nessie_stream_ctx.cipher_enc = (nessie_stream_genenc_fpt)arcfour_gen;
+
+ nessie_stream_run();
+}
/*****************************************************************************