/** 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_init( void *ctx, uint32_t algo, TEE_OperationMode mode, const uint8_t *key, size_t key_len, const uint8_t *nonce, size_t nonce_len, size_t tag_len, size_t aad_len, size_t payload_len) { TEE_Result res; int ltc_res; int ltc_cipherindex; unsigned char *payload, *res_payload; struct tee_ccm_state *ccm; struct tee_gcm_state *gcm; res = tee_algo_to_ltc_cipherindex(algo, <c_cipherindex); if (res != TEE_SUCCESS) return TEE_ERROR_NOT_SUPPORTED; switch (algo) { case TEE_ALG_AES_CCM: /* Check the key length */ if ((!key) || (key_len > TEE_CCM_KEY_MAX_LENGTH)) return TEE_ERROR_BAD_PARAMETERS; /* check the nonce */ if (nonce_len > TEE_CCM_NONCE_MAX_LENGTH) return TEE_ERROR_BAD_PARAMETERS; /* check the tag len */ if ((tag_len < 4) || (tag_len > TEE_CCM_TAG_MAX_LENGTH) || (tag_len % 2 != 0)) return TEE_ERROR_NOT_SUPPORTED; /* allocate payload */ payload = malloc(payload_len + TEE_CCM_KEY_MAX_LENGTH); if (!payload) return TEE_ERROR_OUT_OF_MEMORY; res_payload = malloc(payload_len + TEE_CCM_KEY_MAX_LENGTH); if (!res_payload) { free(payload); return TEE_ERROR_OUT_OF_MEMORY; } /* initialize the structure */ ccm = ctx; memset(ccm, 0, sizeof(struct tee_ccm_state)); memcpy(ccm->key, key, key_len); ccm->key_len = key_len; /* the key length */ if (nonce && nonce_len) { memcpy(ccm->nonce, nonce, nonce_len); ccm->nonce_len = nonce_len; } else { ccm->nonce_len = 0; } ccm->tag_len = tag_len; ccm->aad_len = aad_len; ccm->payload_len = payload_len; ccm->payload = payload; ccm->res_payload = res_payload; ccm->ltc_cipherindex = ltc_cipherindex; if (ccm->aad_len) { ccm->header = malloc(ccm->aad_len); if (!ccm->header) { free(payload); free(res_payload); return TEE_ERROR_OUT_OF_MEMORY; } } /* memset the payload to 0 that will be used for padding */ memset(ccm->payload, 0, payload_len + TEE_CCM_KEY_MAX_LENGTH); break; case TEE_ALG_AES_GCM: /* reset the state */ gcm = ctx; memset(gcm, 0, sizeof(struct tee_gcm_state)); gcm->tag_len = tag_len; ltc_res = gcm_init( &gcm->ctx, ltc_cipherindex, key, key_len); if (ltc_res != CRYPT_OK) return TEE_ERROR_BAD_STATE; /* Add the IV */ ltc_res = gcm_add_iv(&gcm->ctx, nonce, nonce_len); if (ltc_res != CRYPT_OK) return TEE_ERROR_BAD_STATE; break; default: return TEE_ERROR_NOT_SUPPORTED; } return TEE_SUCCESS; }