--- ./cipher.c 2004-02-25 18:27:35.000000000 +0000 +++ /home/agl/src/libgcrypt-1.2.1.agl/cipher/cipher.c 2005-06-14 17:35:11.887795706 +0100 @@ -112,6 +112,10 @@ unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* in IV */ unsigned char ctr[MAX_BLOCKSIZE]; /* For Counter (CTR) mode. */ + unsigned char ctr_buffer[MAX_BLOCKSIZE]; /* Used to store the remains of + a block in the case of a CTR + encrypt which isn't block + aligned */ PROPERLY_ALIGNED_TYPE context; }; @@ -632,6 +636,8 @@ h->module = module; h->mode = mode; h->flags = flags; + h->unused = 0; /* never let the unused value point into space + since it's used as an index in some places */ } } @@ -718,6 +724,7 @@ ivlen = c->cipher->blocksize; memcpy( c->iv, iv, ivlen ); } + c->unused = 0; } @@ -979,25 +986,37 @@ unsigned int nbytes ) { unsigned int n; - byte tmp[MAX_BLOCKSIZE]; int i; + /* CTR mode involves encrypting by XORing with the inf sequence: + * E_k(ctr) | E_k(ctr+1) | ... + * where ctr is the IV for this mode. A block of XOR data + * (the result of E_k(ctr)) is kept in c->ctr_buffer and the + * amount of that buffer which has already been used is kept in + * c->unused (which is a little confusing - think of unused as + * begin an index at which the unused XOR data is)*/ + for(n=0; n < nbytes; n++) { - if ((n % c->cipher->blocksize) == 0) - { - c->cipher->encrypt (&c->context.c, tmp, c->ctr); + if (c->unused == 0 || c->unused == c->cipher->blocksize) + { + // 0 is not a valid value for unused since, + // if a whole block was left over it wouldn't have been + // generated in the first place. Thus it means `need a + // new buffer' + c->cipher->encrypt (&c->context.c, c->ctr_buffer, c->ctr); + // increment the value of ctr for (i = c->cipher->blocksize; i > 0; i--) { c->ctr[i-1]++; if (c->ctr[i-1] != 0) break; } - } - /* XOR input with encrypted counter and store in output. */ - outbuf[n] = inbuf[n] ^ tmp[n % c->cipher->blocksize]; + c->unused = 0; + } + outbuf[n] = inbuf[n] ^ c->ctr_buffer[c->unused++]; } }