static void safexcel_aead_token()

in inside-secure/safexcel_cipher.c [161:370]


static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
				struct safexcel_command_desc *cdesc,
				struct safexcel_token *atoken,
				enum safexcel_cipher_direction direction,
				u32 cryptlen, u32 assoclen, u32 digestsize)
{
	struct safexcel_token *aadref;
	int atoksize = 2; /* Start with minimum size */
	int assocadj = assoclen - ctx->aadskip, aadalign;

	/* Always 4 dwords of embedded IV  for AEAD modes */
	cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;

	if (direction == SAFEXCEL_DECRYPT)
		cryptlen -= digestsize;

	if (unlikely(ctx->xcm == EIP197_XCM_MODE_CCM)) {
		/* Construct IV block B0 for the CBC-MAC */
		u8 *final_iv = (u8 *)cdesc->control_data.token;
		u8 *cbcmaciv = (u8 *)&atoken[1];
		__le32 *aadlen = (__le32 *)&atoken[5];

		if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
			/* Length + nonce */
			cdesc->control_data.token[0] = ctx->nonce;
			/* Fixup flags byte */
			*(__le32 *)cbcmaciv =
				cpu_to_le32(ctx->nonce |
					    ((assocadj > 0) << 6) |
					    ((digestsize - 2) << 2));
			/* 64 bit IV part */
			memcpy(&cdesc->control_data.token[1], iv, 8);
			memcpy(cbcmaciv + 4, iv, 8);
			/* Start counter at 0 */
			cdesc->control_data.token[3] = 0;
			/* Message length */
			*(__be32 *)(cbcmaciv + 12) = cpu_to_be32(cryptlen);
		} else {
			/* Variable length IV part */
			memcpy(final_iv, iv, 15 - iv[0]);
			memcpy(cbcmaciv, iv, 15 - iv[0]);
			/* Start variable length counter at 0 */
			memset(final_iv + 15 - iv[0], 0, iv[0] + 1);
			memset(cbcmaciv + 15 - iv[0], 0, iv[0] - 1);
			/* fixup flags byte */
			cbcmaciv[0] |= ((assocadj > 0) << 6) |
				       ((digestsize - 2) << 2);
			/* insert lower 2 bytes of message length */
			cbcmaciv[14] = cryptlen >> 8;
			cbcmaciv[15] = cryptlen & 255;
		}

		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
		atoken->packet_length = AES_BLOCK_SIZE +
					((assocadj > 0) << 1);
		atoken->stat = 0;
		atoken->instructions = EIP197_TOKEN_INS_ORIGIN_TOKEN |
				       EIP197_TOKEN_INS_TYPE_HASH;

		if (likely(assocadj)) {
			*aadlen = cpu_to_le32((assocadj >> 8) |
					      (assocadj & 255) << 8);
			atoken += 6;
			atoksize += 7;
		} else {
			atoken += 5;
			atoksize += 6;
		}

		/* Process AAD data */
		aadref = atoken;
		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
		atoken->packet_length = assocadj;
		atoken->stat = 0;
		atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
		atoken++;

		/* For CCM only, align AAD data towards hash engine */
		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
		aadalign = (assocadj + 2) & 15;
		atoken->packet_length = assocadj && aadalign ?
						16 - aadalign :
						0;
		if (likely(cryptlen)) {
			atoken->stat = 0;
			atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
		} else {
			atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
			atoken->instructions = EIP197_TOKEN_INS_LAST |
					       EIP197_TOKEN_INS_TYPE_HASH;
		}
	} else {
		safexcel_aead_iv(ctx, iv, cdesc);

		/* Process AAD data */
		aadref = atoken;
		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
		atoken->packet_length = assocadj;
		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
		atoken->instructions = EIP197_TOKEN_INS_LAST |
				       EIP197_TOKEN_INS_TYPE_HASH;
	}
	atoken++;

	if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
		/* For ESP mode (and not GMAC), skip over the IV */
		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
		atoken->packet_length = EIP197_AEAD_IPSEC_IV_SIZE;
		atoken->stat = 0;
		atoken->instructions = 0;
		atoken++;
		atoksize++;
	} else if (unlikely(ctx->alg == SAFEXCEL_CHACHA20 &&
			    direction == SAFEXCEL_DECRYPT)) {
		/* Poly-chacha decryption needs a dummy NOP here ... */
		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
		atoken->packet_length = 16; /* According to Op Manual */
		atoken->stat = 0;
		atoken->instructions = 0;
		atoken++;
		atoksize++;
	}

	if  (ctx->xcm) {
		/* For GCM and CCM, obtain enc(Y0) */
		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT_REMRES;
		atoken->packet_length = 0;
		atoken->stat = 0;
		atoken->instructions = AES_BLOCK_SIZE;
		atoken++;

		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
		atoken->packet_length = AES_BLOCK_SIZE;
		atoken->stat = 0;
		atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
				       EIP197_TOKEN_INS_TYPE_CRYPTO;
		atoken++;
		atoksize += 2;
	}

	if (likely(cryptlen || ctx->alg == SAFEXCEL_CHACHA20)) {
		/* Fixup stat field for AAD direction instruction */
		aadref->stat = 0;

		/* Process crypto data */
		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
		atoken->packet_length = cryptlen;

		if (unlikely(ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP_GMAC)) {
			/* Fixup instruction field for AAD dir instruction */
			aadref->instructions = EIP197_TOKEN_INS_TYPE_HASH;

			/* Do not send to crypt engine in case of GMAC */
			atoken->instructions = EIP197_TOKEN_INS_LAST |
					       EIP197_TOKEN_INS_TYPE_HASH |
					       EIP197_TOKEN_INS_TYPE_OUTPUT;
		} else {
			atoken->instructions = EIP197_TOKEN_INS_LAST |
					       EIP197_TOKEN_INS_TYPE_CRYPTO |
					       EIP197_TOKEN_INS_TYPE_HASH |
					       EIP197_TOKEN_INS_TYPE_OUTPUT;
		}

		cryptlen &= 15;
		if (unlikely(ctx->xcm == EIP197_XCM_MODE_CCM && cryptlen)) {
			atoken->stat = 0;
			/* For CCM only, pad crypto data to the hash engine */
			atoken++;
			atoksize++;
			atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
			atoken->packet_length = 16 - cryptlen;
			atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
			atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
		} else {
			atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
		}
		atoken++;
		atoksize++;
	}

	if (direction == SAFEXCEL_ENCRYPT) {
		/* Append ICV */
		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
		atoken->packet_length = digestsize;
		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
			       EIP197_TOKEN_STAT_LAST_PACKET;
		atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
				       EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
	} else {
		/* Extract ICV */
		atoken->opcode = EIP197_TOKEN_OPCODE_RETRIEVE;
		atoken->packet_length = digestsize;
		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
			       EIP197_TOKEN_STAT_LAST_PACKET;
		atoken->instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
		atoken++;
		atoksize++;

		/* Verify ICV */
		atoken->opcode = EIP197_TOKEN_OPCODE_VERIFY;
		atoken->packet_length = digestsize |
					EIP197_TOKEN_HASH_RESULT_VERIFY;
		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
			       EIP197_TOKEN_STAT_LAST_PACKET;
		atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT;
	}

	/* Fixup length of the token in the command descriptor */
	cdesc->additional_cdata_size = atoksize;
}