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;
}