On Wed, 2007-10-03 at 18:21 +0800, Herbert Xu wrote:
> We can't assume that the counter block is always 16 bytes
> since that depends on the underlying block size. It's probably
> easiest if the caller computes the correct counter position and
> gives that to us.
>
> BTW, it isn't that hard to support arbitrary counter sizes so
> we should fix that too and remove the counter size == 4 check.
>
> Here's how you can do it:
>
> static void ctr_inc_32(u8 *a, int size)
> {
> __be32 *b = (__be32 *)a;
>
> *b = cpu_to_be32(be32_to_cpu(*b) + 1);
> }
>
> static void __ctr_inc_byte(u8 *a, int size)
> {
> __be8 *b = (__be8 *)(a + size);
> u8 c;
>
> do {
> c = be8_to_cpu(*--b) + 1;
> *b = cpu_to_be8(c);
> if (c)
> break;
> } while (--size);
> }
>
> static void ctr_inc_quad(u8 *a, int size)
> {
> __be32 *b = (__be32 *)(a + size);
> u32 c;
>
> for (; size >= 4; size -= 4) {
> c = be32_to_cpu(*--b) + 1;
> *b = cpu_to_be32(c);
> if (c)
> return;
> }
>
> __ctr_inc_byte(a, size);
> }
>
I really like this! Something else I should have thought of. :-)
> > + do {
> > + /* create keystream */
> > + fn(crypto_cipher_tfm(tfm), dst, ctrblk);
> > + xor(dst, src, bsize);
> > +
> > + /* increment counter in counterblock */
> > + ctr_inc((__be32 *)ctrblk);
> > +
> > + src += bsize;
> > + dst += bsize;
> > + } while ((nbytes -= bsize) >= bsize);
>
> As I mentioned above we need to deal with partial blocks at
> the end. The easiest way is to change the loop termination
> to:
>
> if (nbytes < bsize)
> break;
> nbytes -= bsize;
>
> and change
>
> xor(dst, src, bsize);
>
> to
>
> xor(dst, src, min(nbytes, bsize));
Ok. Also, I assumed the data we passed to the cipher
algorithms such as aes, des, etc... must be in blocks of blocksize.
Since the last block of data to CTR may be a partial block, I changed
the following in crypto_ctr_crypt_segment(),
/* create keystream */
fn(crypto_cipher_tfm(tfm), dst, ctrblk);
xor_quad(dst, src, min(nbytes, bsize));
to
/* create keystream */
fn(crypto_cipher_tfm(tfm), keystream, ctrblk);
xor_quad(keystream, src, min(nbytes, bsize));
memcpy(dst, keystream, min(nbytes, bsize));
I also changed it such that we return 0 instead of nbytes.
This brings up another question...
In the encrypt function, there's the loop,
while (walk.nbytes) {
if (walk.src.virt.addr == walk.dst.virt.addr)
nbytes = crypto_ctr_crypt_inplace(&walk, ctx,
counterblk,
countersize);
else
nbytes = crypto_ctr_crypt_segment(&walk, ctx
counterblk,
countersize);
err = blkcipher_walk_done(desc, &walk, nbytes);
}
I assumed that if there is a partial block, it will occur at the
very end of all the data. However, looking at this loop, I wondered
if it was possible to get a partial block somewhere other than the end
while stepping through this loop?
I tried looking through blkcipher.c code, but figured I'd do better
just asking the question. :-)
> > +static int crypto_ctr_encrypt(struct blkcipher_desc *desc,
> > + struct scatterlist *dst, struct scatterlist *src,
> > + unsigned int nbytes)
> > +{
> > + struct blkcipher_walk walk;
> > + struct crypto_blkcipher *tfm = desc->tfm;
> > + struct crypto_ctr_ctx *ctx = crypto_blkcipher_ctx(tfm);
> > + struct crypto_cipher *child = ctx->child;
> > + int bsize = crypto_cipher_blocksize(child);
> > + struct ctr_instance_ctx *ictx =
> > + crypto_instance_ctx(crypto_tfm_alg_instance(&tfm->base));
> > + u8 counterblk[bsize];
>
> This needs to be aligned by the underlying mask and at least 4.
>
Ok, sorry I missed that.
However, I don't understand what the check
for 4 is for... my bsize should be at least 4?
Will get a new patch out to you shortly.
Thanks!!
Joy
-
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html