static int ctr_paes_crypt(struct blkcipher_desc *desc, unsigned long modifier, struct blkcipher_walk *walk) { struct s390_paes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); u8 buf[AES_BLOCK_SIZE], *ctrptr; unsigned int nbytes, n, k; int ret, locked; locked = spin_trylock(&ctrblk_lock); ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { n = AES_BLOCK_SIZE; if (nbytes >= 2*AES_BLOCK_SIZE && locked) n = __ctrblk_init(ctrblk, walk->iv, nbytes); ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv; k = cpacf_kmctr(ctx->fc | modifier, ctx->pk.protkey, walk->dst.virt.addr, walk->src.virt.addr, n, ctrptr); if (k) { if (ctrptr == ctrblk) memcpy(walk->iv, ctrptr + k - AES_BLOCK_SIZE, AES_BLOCK_SIZE); crypto_inc(walk->iv, AES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, nbytes - n); } if (k < n) { if (__ctr_paes_set_key(ctx) != 0) { if (locked) spin_unlock(&ctrblk_lock); return blkcipher_walk_done(desc, walk, -EIO); } } } if (locked) spin_unlock(&ctrblk_lock); /* * final block may be < AES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { while (1) { if (cpacf_kmctr(ctx->fc | modifier, ctx->pk.protkey, buf, walk->src.virt.addr, AES_BLOCK_SIZE, walk->iv) == AES_BLOCK_SIZE) break; if (__ctr_paes_set_key(ctx) != 0) return blkcipher_walk_done(desc, walk, -EIO); } memcpy(walk->dst.virt.addr, buf, nbytes); crypto_inc(walk->iv, AES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); } return ret; }
static int ctr_desall_crypt(struct blkcipher_desc *desc, unsigned long fc, struct blkcipher_walk *walk) { struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); u8 buf[DES_BLOCK_SIZE], *ctrptr; unsigned int n, nbytes; int ret, locked; locked = spin_trylock(&ctrblk_lock); ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { n = DES_BLOCK_SIZE; if (nbytes >= 2*DES_BLOCK_SIZE && locked) n = __ctrblk_init(ctrblk, walk->iv, nbytes); ctrptr = (n > DES_BLOCK_SIZE) ? ctrblk : walk->iv; cpacf_kmctr(fc, ctx->key, walk->dst.virt.addr, walk->src.virt.addr, n, ctrptr); if (ctrptr == ctrblk) memcpy(walk->iv, ctrptr + n - DES_BLOCK_SIZE, DES_BLOCK_SIZE); crypto_inc(walk->iv, DES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, nbytes - n); } if (locked) spin_unlock(&ctrblk_lock); /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { cpacf_kmctr(fc, ctx->key, buf, walk->src.virt.addr, DES_BLOCK_SIZE, walk->iv); memcpy(walk->dst.virt.addr, buf, nbytes); crypto_inc(walk->iv, DES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); } return ret; }
static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, struct s390_des_ctx *ctx, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); unsigned int n, nbytes; u8 buf[DES_BLOCK_SIZE], ctrbuf[DES_BLOCK_SIZE]; u8 *out, *in, *ctrptr = ctrbuf; if (!walk->nbytes) return ret; if (spin_trylock(&ctrblk_lock)) ctrptr = ctrblk; memcpy(ctrptr, walk->iv, DES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { out = walk->dst.virt.addr; in = walk->src.virt.addr; while (nbytes >= DES_BLOCK_SIZE) { if (ctrptr == ctrblk) n = __ctrblk_init(ctrptr, nbytes); else n = DES_BLOCK_SIZE; ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrptr); if (ret < 0 || ret != n) { if (ctrptr == ctrblk) spin_unlock(&ctrblk_lock); return -EIO; } if (n > DES_BLOCK_SIZE) memcpy(ctrptr, ctrptr + n - DES_BLOCK_SIZE, DES_BLOCK_SIZE); crypto_inc(ctrptr, DES_BLOCK_SIZE); out += n; in += n; nbytes -= n; } ret = blkcipher_walk_done(desc, walk, nbytes); } if (ctrptr == ctrblk) { if (nbytes) memcpy(ctrbuf, ctrptr, DES_BLOCK_SIZE); else memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); spin_unlock(&ctrblk_lock); } else { if (!nbytes) memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); } /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { out = walk->dst.virt.addr; in = walk->src.virt.addr; ret = crypt_s390_kmctr(func, ctx->key, buf, in, DES_BLOCK_SIZE, ctrbuf); if (ret < 0 || ret != DES_BLOCK_SIZE) return -EIO; memcpy(out, buf, nbytes); crypto_inc(ctrbuf, DES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); memcpy(walk->iv, ctrbuf, DES_BLOCK_SIZE); } return ret; }