crypto/skcipher.c

Source file repositories/reference/linux-study-clean/crypto/skcipher.c

File Facts

System
Linux kernel
Corpus path
crypto/skcipher.c
Extension
.c
Size
24424 bytes
Lines
887
Domain
Kernel Services
Bucket
crypto
Inferred role
Kernel Services: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Shared kernel service surface used by multiple subsystems, including helpers, cryptography, virtualization support, and async I/O infrastructure.

Dependency Surface

Detected Declarations

Annotated Snippet

if (res > 0) {
			/*
			 * Didn't process all bytes.  Either the algorithm is
			 * broken, or this was the last step and it turned out
			 * the message wasn't evenly divisible into blocks but
			 * the algorithm requires it.
			 */
			res = -EINVAL;
			total = 0;
		} else
			memcpy_to_scatterwalk(&walk->out, walk->out.addr, n);
		goto dst_done;
	}

	scatterwalk_done_dst(&walk->out, n);
dst_done:

	if (res > 0)
		res = 0;

	walk->total = total;
	walk->nbytes = 0;

	if (total) {
		if (walk->flags & SKCIPHER_WALK_SLEEP)
			cond_resched();
		walk->flags &= ~(SKCIPHER_WALK_SLOW | SKCIPHER_WALK_COPY |
				 SKCIPHER_WALK_DIFF);
		return skcipher_walk_next(walk);
	}

finish:
	/* Short-circuit for the common/fast path. */
	if (!((unsigned long)walk->buffer | (unsigned long)walk->page))
		goto out;

	if (walk->iv != walk->oiv)
		memcpy(walk->oiv, walk->iv, walk->ivsize);
	if (walk->buffer != walk->page)
		kfree(walk->buffer);
	if (walk->page)
		free_page((unsigned long)walk->page);

out:
	return res;
}
EXPORT_SYMBOL_GPL(skcipher_walk_done);

static int skcipher_next_slow(struct skcipher_walk *walk, unsigned int bsize)
{
	unsigned alignmask = walk->alignmask;
	unsigned n;
	void *buffer;

	if (!walk->buffer)
		walk->buffer = walk->page;
	buffer = walk->buffer;
	if (!buffer) {
		/* Min size for a buffer of bsize bytes aligned to alignmask */
		n = bsize + (alignmask & ~(crypto_tfm_ctx_alignment() - 1));

		buffer = kzalloc(n, skcipher_walk_gfp(walk));
		if (!buffer)
			return skcipher_walk_done(walk, -ENOMEM);
		walk->buffer = buffer;
	}

	buffer = PTR_ALIGN(buffer, alignmask + 1);
	memcpy_from_scatterwalk(buffer, &walk->in, bsize);
	walk->out.__addr = buffer;
	walk->in.__addr = walk->out.addr;

	walk->nbytes = bsize;
	walk->flags |= SKCIPHER_WALK_SLOW;

	return 0;
}

static int skcipher_next_copy(struct skcipher_walk *walk)
{
	void *tmp = walk->page;

	scatterwalk_map(&walk->in);
	memcpy(tmp, walk->in.addr, walk->nbytes);
	scatterwalk_unmap(&walk->in);
	/*
	 * walk->in is advanced later when the number of bytes actually
	 * processed (which might be less than walk->nbytes) is known.
	 */

Annotation

Implementation Notes