static int blkcipher_walk_first(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { struct crypto_blkcipher *tfm = desc->tfm; unsigned int alignmask = crypto_blkcipher_alignmask(tfm); if (WARN_ON_ONCE(in_irq())) return -EDEADLK; walk->nbytes = walk->total; if (unlikely(!walk->total)) return 0; walk->buffer = NULL; walk->iv = desc->info; if (unlikely(((unsigned long)walk->iv & alignmask))) { int err = blkcipher_copy_iv(walk, tfm, alignmask); if (err) return err; } scatterwalk_start(&walk->in, walk->in.sg); scatterwalk_start(&walk->out, walk->out.sg); walk->page = NULL; return blkcipher_walk_next(desc, walk); }
static int crypto_rfc3686_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { struct crypto_blkcipher *tfm = desc->tfm; struct crypto_rfc3686_ctx *ctx = crypto_blkcipher_ctx(tfm); struct crypto_blkcipher *child = ctx->child; unsigned long alignmask = crypto_blkcipher_alignmask(tfm); u8 ivblk[CTR_RFC3686_BLOCK_SIZE + alignmask]; u8 *iv = PTR_ALIGN(ivblk + 0, alignmask + 1); u8 *info = desc->info; int err; /* set up counter block */ memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE); /* initialize counter portion of counter block */ *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = cpu_to_be32(1); desc->tfm = child; desc->info = iv; err = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); desc->tfm = tfm; desc->info = info; return err; }
int blkcipher_walk_phys(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { walk->flags |= BLKCIPHER_WALK_PHYS; walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); walk->cipher_blocksize = walk->walk_blocksize; walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); return blkcipher_walk_first(desc, walk); }
static int blkcipher_walk_next(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { struct crypto_blkcipher *tfm = desc->tfm; unsigned int alignmask = crypto_blkcipher_alignmask(tfm); unsigned int bsize; unsigned int n; int err; n = walk->total; if (unlikely(n < crypto_blkcipher_blocksize(tfm))) { desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; return blkcipher_walk_done(desc, walk, -EINVAL); } walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY | BLKCIPHER_WALK_DIFF); if (!scatterwalk_aligned(&walk->in, alignmask) || !scatterwalk_aligned(&walk->out, alignmask) || (walk->flags & AMBA_CIPHER_COPY)) { walk->flags |= BLKCIPHER_WALK_COPY; if (!walk->page) { walk->page = (void *)__get_free_page(GFP_ATOMIC); if (!walk->page) n = 0; } } bsize = min(walk->blocksize, n); n = scatterwalk_clamp(&walk->in, n); n = scatterwalk_clamp(&walk->out, n); if (unlikely(n < bsize)) { err = blkcipher_next_slow(desc, walk, bsize, alignmask); goto set_phys_lowmem; } walk->nbytes = n; if (walk->flags & BLKCIPHER_WALK_COPY) { err = blkcipher_next_copy(walk); goto set_phys_lowmem; } return blkcipher_next_fast(desc, walk); set_phys_lowmem: if (walk->flags & BLKCIPHER_WALK_PHYS) { walk->src.phys.page = virt_to_page(walk->src.virt.addr); walk->dst.phys.page = virt_to_page(walk->dst.virt.addr); walk->src.phys.offset &= PAGE_SIZE - 1; walk->dst.phys.offset &= PAGE_SIZE - 1; } return err; }
int blkcipher_walk_virt_block(struct blkcipher_desc *desc, struct blkcipher_walk *walk, unsigned int blocksize) { walk->flags &= ~BLKCIPHER_WALK_PHYS; walk->walk_blocksize = blocksize; walk->cipher_blocksize = crypto_blkcipher_blocksize(desc->tfm); walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); return blkcipher_walk_first(desc, walk); }
static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm, struct blkcipher_walk *walk, unsigned int bsize) { u8 *addr; unsigned int alignmask = crypto_blkcipher_alignmask(tfm); addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); addr = blkcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, 1); return bsize; }