/** Process an entire GCM packet in one call. @param cipher Index of cipher to use @param key The secret key @param keylen The length of the secret key @param IV The initial vector @param IVlen The length of the initial vector @param adata The additional authentication data (header) @param adatalen The length of the adata @param pt The plaintext @param ptlen The length of the plaintext (ciphertext length is the same) @param ct The ciphertext @param tag [out] The MAC tag @param taglen [in/out] The MAC tag length @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT) @return CRYPT_OK on success */ int gcm_memory( int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *IV, unsigned long IVlen, const unsigned char *adata, unsigned long adatalen, unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tag, unsigned long *taglen, int direction) { void *orig; gcm_state *gcm; int err; if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { return err; } if (cipher_descriptor[cipher].accel_gcm_memory != NULL) { return cipher_descriptor[cipher].accel_gcm_memory (key, keylen, IV, IVlen, adata, adatalen, pt, ptlen, ct, tag, taglen, direction); } #ifndef LTC_GCM_TABLES_SSE2 orig = gcm = XMALLOC(sizeof(*gcm)); #else orig = gcm = XMALLOC(sizeof(*gcm) + 16); #endif if (gcm == NULL) { return CRYPT_MEM; } /* Force GCM to be on a multiple of 16 so we can use 128-bit aligned operations * note that we only modify gcm and keep orig intact. This code is not portable * but again it's only for SSE2 anyways, so who cares? */ #ifdef LTC_GCM_TABLES_SSE2 if ((unsigned long)gcm & 15) { gcm = (gcm_state *)((unsigned long)gcm + (16 - ((unsigned long)gcm & 15))); } #endif if ((err = gcm_init(gcm, cipher, key, keylen)) != CRYPT_OK) { goto LTC_ERR; } if ((err = gcm_add_iv(gcm, IV, IVlen)) != CRYPT_OK) { goto LTC_ERR; } if ((err = gcm_add_aad(gcm, adata, adatalen)) != CRYPT_OK) { goto LTC_ERR; } if ((err = gcm_process(gcm, pt, ptlen, ct, direction)) != CRYPT_OK) { goto LTC_ERR; } err = gcm_done(gcm, tag, taglen); LTC_ERR: XFREE(orig); return err; }
TEE_Result tee_authenc_update_payload( void *ctx, uint32_t algo, TEE_OperationMode mode, const uint8_t *src_data, size_t src_len, uint8_t *dst_data) { TEE_Result res; int ltc_res, dir; struct tee_ccm_state *ccm; struct tee_gcm_state *gcm; unsigned char *pt, *ct; /* the plain and the cipher text */ if (mode == TEE_MODE_ENCRYPT) { pt = (unsigned char *)src_data; ct = dst_data; } else { pt = dst_data; ct = (unsigned char *)src_data; } switch (algo) { case TEE_ALG_AES_CCM: /* Check aad has been correctly added */ ccm = ctx; if (ccm->aad_len != ccm->header_len) return TEE_ERROR_BAD_STATE; /* * check we do not add more data than what was defined at * the init */ if (ccm->current_payload_len + src_len > ccm->payload_len) return TEE_ERROR_BAD_PARAMETERS; memcpy(ccm->payload + ccm->current_payload_len, src_data, src_len); ccm->current_payload_len += src_len; dir = (mode == TEE_MODE_ENCRYPT ? CCM_ENCRYPT : CCM_DECRYPT); ltc_res = ccm_memory( ccm->ltc_cipherindex, ccm->key, ccm->key_len, 0, /* not presecheduled */ ccm->nonce, ccm->nonce_len, ccm->header, ccm->header_len, pt, src_len, ct, ccm->tag, &ccm->tag_len, dir); if (ltc_res != CRYPT_OK) return TEE_ERROR_BAD_STATE; break; case TEE_ALG_AES_GCM: /* aad is optional ==> add one without length */ gcm = ctx; if (gcm->ctx.mode == LTC_GCM_MODE_IV) { res = tee_authenc_update_aad( &gcm->ctx, algo, mode, 0, 0); if (res != TEE_SUCCESS) return res; } /* process the data */ dir = (mode == TEE_MODE_ENCRYPT ? GCM_ENCRYPT : GCM_DECRYPT); ltc_res = gcm_process(&gcm->ctx, pt, src_len, ct, dir); if (ltc_res != CRYPT_OK) return TEE_ERROR_BAD_STATE; break; default: return TEE_ERROR_NOT_SUPPORTED; } return TEE_SUCCESS; }