arch/arm64/crypto/sm4-ce-gcm-glue.c

Source file repositories/reference/linux-study-clean/arch/arm64/crypto/sm4-ce-gcm-glue.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/crypto/sm4-ce-gcm-glue.c
Extension
.c
Size
6591 bytes
Lines
263
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sm4_gcm_ctx {
	struct sm4_ctx key;
	u8 ghash_table[16 * 4];
};


static int gcm_setkey(struct crypto_aead *tfm, const u8 *key,
		      unsigned int key_len)
{
	struct sm4_gcm_ctx *ctx = crypto_aead_ctx(tfm);

	if (key_len != SM4_KEY_SIZE)
		return -EINVAL;

	scoped_ksimd() {
		sm4_ce_expand_key(key, ctx->key.rkey_enc, ctx->key.rkey_dec,
				crypto_sm4_fk, crypto_sm4_ck);
		sm4_ce_pmull_ghash_setup(ctx->key.rkey_enc, ctx->ghash_table);
	}
	return 0;
}

static int gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
	switch (authsize) {
	case 4:
	case 8:
	case 12 ... 16:
		return 0;
	default:
		return -EINVAL;
	}
}

static void gcm_calculate_auth_mac(struct aead_request *req, u8 ghash[])
{
	struct crypto_aead *aead = crypto_aead_reqtfm(req);
	struct sm4_gcm_ctx *ctx = crypto_aead_ctx(aead);
	u8 __aligned(8) buffer[GHASH_BLOCK_SIZE];
	u32 assoclen = req->assoclen;
	struct scatter_walk walk;
	unsigned int buflen = 0;

	scatterwalk_start(&walk, req->src);

	do {
		unsigned int n, orig_n;
		const u8 *p;

		orig_n = scatterwalk_next(&walk, assoclen);
		p = walk.addr;
		n = orig_n;

		if (n + buflen < GHASH_BLOCK_SIZE) {
			memcpy(&buffer[buflen], p, n);
			buflen += n;
		} else {
			unsigned int nblocks;

			if (buflen) {
				unsigned int l = GHASH_BLOCK_SIZE - buflen;

				memcpy(&buffer[buflen], p, l);
				p += l;
				n -= l;

				pmull_ghash_update(ctx->ghash_table, ghash,
						   buffer, 1);
			}

			nblocks = n / GHASH_BLOCK_SIZE;
			if (nblocks) {
				pmull_ghash_update(ctx->ghash_table, ghash,
						   p, nblocks);
				p += nblocks * GHASH_BLOCK_SIZE;
			}

			buflen = n % GHASH_BLOCK_SIZE;
			if (buflen)
				memcpy(&buffer[0], p, buflen);
		}

		scatterwalk_done_src(&walk, orig_n);
		assoclen -= orig_n;
	} while (assoclen);

	/* padding with '0' */
	if (buflen) {
		memset(&buffer[buflen], 0, GHASH_BLOCK_SIZE - buflen);
		pmull_ghash_update(ctx->ghash_table, ghash, buffer, 1);

Annotation

Implementation Notes