Exemplo n.º 1
0
TEE_Result tee_do_cipher_update(void *ctx, uint32_t algo,
				TEE_OperationMode mode, bool last_block,
				const uint8_t *data, size_t len, uint8_t *dst)
{
	TEE_Result res;
	size_t block_size;

	if (mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT)
		return TEE_ERROR_BAD_PARAMETERS;

	/*
	 * Check that the block contains the correct number of data, apart
	 * for the last block in some XTS / CTR / XTS mode
	 */
	res = tee_cipher_get_block_size(algo, &block_size);
	if (res != TEE_SUCCESS)
		return res;
	if ((len % block_size) != 0) {
		if (!last_block && algo != TEE_ALG_AES_CTR)
			return TEE_ERROR_BAD_PARAMETERS;

		switch (algo) {
		case TEE_ALG_AES_ECB_NOPAD:
		case TEE_ALG_DES_ECB_NOPAD:
		case TEE_ALG_DES3_ECB_NOPAD:
		case TEE_ALG_AES_CBC_NOPAD:
		case TEE_ALG_DES_CBC_NOPAD:
		case TEE_ALG_DES3_CBC_NOPAD:
			return TEE_ERROR_BAD_PARAMETERS;

		case TEE_ALG_AES_CTR:
		case TEE_ALG_AES_XTS:
		case TEE_ALG_AES_CTS:
			/*
			 * These modes doesn't require padding for the last
			 * block.
			 *
			 * This isn't entirely true, both XTS and CTS can only
			 * encrypt minimum one block and also they need at least
			 * one complete block in the last update to finish the
			 * encryption. The algorithms are supposed to detect
			 * that, we're only making sure that all data fed up to
			 * that point consists of complete blocks.
			 */
			break;

		default:
			return TEE_ERROR_NOT_SUPPORTED;
		}
	}

	return crypto_cipher_update(ctx, algo, mode, last_block, data, len,
				    dst);
}
Exemplo n.º 2
0
TEE_Result tee_authenc_dec_final(
	void *ctx, uint32_t algo, const uint8_t *src_data,
	size_t src_len, uint8_t *dst_data, const uint8_t *tag, size_t tag_len)
{
	TEE_Result res = TEE_ERROR_BAD_STATE;
	struct tee_ccm_state *ccm;
	struct tee_gcm_state *gcm;
	int ltc_res;
	uint8_t dst_tag[TEE_xCM_TAG_MAX_LENGTH];
	size_t dst_len, init_len;
	unsigned long ltc_tag_len = tag_len;

	res = tee_cipher_get_block_size(algo, &dst_len);
	if (res != TEE_SUCCESS)
		return res;
	if (tag_len == 0)
		return TEE_ERROR_SHORT_BUFFER;
	if (tag_len > TEE_xCM_TAG_MAX_LENGTH)
		return TEE_ERROR_BAD_STATE;

	switch (algo) {
	case TEE_ALG_AES_CCM:
		ccm = ctx;

		init_len = ccm->current_payload_len;
		if (src_len) {
			memcpy(ccm->payload + ccm->current_payload_len,
			       src_data, src_len);
			ccm->current_payload_len += src_len;
		}

		if (ccm->payload_len != ccm->current_payload_len)
			return TEE_ERROR_BAD_PARAMETERS;

		ltc_res = ccm_memory(
			ccm->ltc_cipherindex,
			ccm->key, ccm->key_len,
			0,	/* not previously scheduled */
			ccm->nonce,  ccm->nonce_len,
			ccm->header, ccm->header_len,
			ccm->res_payload,
			ccm->current_payload_len, ccm->payload,
			dst_tag, &ltc_tag_len, CCM_DECRYPT);
		if (ltc_res != CRYPT_OK)
			return TEE_ERROR_BAD_STATE;

		if (src_len)
			memcpy(dst_data, ccm->res_payload + init_len, src_len);
		break;


	case TEE_ALG_AES_GCM:
		/* Process the last buffer, if any */
		gcm = ctx;
		res = tee_authenc_update_payload(
			&gcm->ctx, algo, TEE_MODE_DECRYPT,
			src_data, src_len, dst_data);
		if (res != TEE_SUCCESS)
			return res;

		/* Finalize the authentication */
		ltc_res = gcm_done(&gcm->ctx, dst_tag, &ltc_tag_len);
		if (ltc_res != CRYPT_OK)
			return TEE_ERROR_BAD_STATE;
		break;

	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}

	if (buf_compare_ct(dst_tag, tag, tag_len) != 0)
		res = TEE_ERROR_MAC_INVALID;
	else
		res = TEE_SUCCESS;
	return res;
}
Exemplo n.º 3
0
TEE_Result tee_authenc_enc_final(
	void *ctx, uint32_t algo, const uint8_t *src_data,
	size_t src_len, uint8_t *dst_data,
	uint8_t *dst_tag, size_t *dst_tag_len)
{
	TEE_Result res, final_res = TEE_ERROR_MAC_INVALID;
	struct tee_ccm_state *ccm;
	struct tee_gcm_state *gcm;
	size_t digest_size;
	int ltc_res;
	int init_len;

	/* Check the resulting buffer is not too short */
	res = tee_cipher_get_block_size(algo, &digest_size);
	if (res != TEE_SUCCESS) {
		final_res = res;
		goto out;
	}

	switch (algo) {
	case TEE_ALG_AES_CCM:
		ccm = ctx;

		init_len = ccm->current_payload_len;
		if (src_len) {
			memcpy(ccm->payload + ccm->current_payload_len,
			       src_data, src_len);
			ccm->current_payload_len += src_len;
		}

		if (ccm->payload_len != ccm->current_payload_len)
			return TEE_ERROR_BAD_PARAMETERS;

		if (*dst_tag_len < ccm->tag_len) {
			*dst_tag_len = ccm->tag_len;
			return TEE_ERROR_SHORT_BUFFER;
		}
		*dst_tag_len = ccm->tag_len;

		ltc_res = ccm_memory(
			ccm->ltc_cipherindex,
			ccm->key, ccm->key_len,
			0,	/* not previously scheduled */
			ccm->nonce,  ccm->nonce_len,
			ccm->header, ccm->header_len,
			ccm->payload, ccm->current_payload_len,
			ccm->res_payload,
			dst_tag, (unsigned long *)dst_tag_len, CCM_ENCRYPT);
		if (ltc_res != CRYPT_OK)
			return TEE_ERROR_BAD_STATE;
		if (src_len)
			memcpy(dst_data, ccm->res_payload + init_len, src_len);
		break;

	case TEE_ALG_AES_GCM:
		/* Finalize the remaining buffer */
		gcm = ctx;
		res = tee_authenc_update_payload(
			&gcm->ctx, algo, TEE_MODE_ENCRYPT,
			src_data, src_len, dst_data);
		if (res != TEE_SUCCESS) {
			final_res = res;
			goto out;
		}

		if (*dst_tag_len < gcm->tag_len) {
			*dst_tag_len = gcm->tag_len;
			return TEE_ERROR_SHORT_BUFFER;
		}
		*dst_tag_len = gcm->tag_len;

		/* Process the last buffer, if any */
		ltc_res = gcm_done(
			&gcm->ctx,
			dst_tag, (unsigned long *)dst_tag_len);
		if (ltc_res != CRYPT_OK)
			goto out;
		break;

	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}
	final_res = TEE_SUCCESS;

out:
	return final_res;
}
Exemplo n.º 4
0
TEE_Result tee_cipher_update(void *ctx, uint32_t algo,
			     TEE_OperationMode mode, bool last_block,
			     const uint8_t *data, size_t len, uint8_t *dst)
{
	TEE_Result res;
	int ltc_res = CRYPT_OK;
	size_t block_size;
	uint8_t tmp_block[64], tmp2_block[64];
	int nb_blocks, len_last_block;
	struct symmetric_CTS *cts;

	/*
	 * Check that the block contains the correct number of data, apart
	 * for the last block in some XTS / CTR / XTS mode
	 */
	res = tee_cipher_get_block_size(algo, &block_size);
	if (res != TEE_SUCCESS)
		return res;
	if ((len % block_size) != 0) {
		if (!last_block)
			return TEE_ERROR_BAD_PARAMETERS;

		switch (algo) {
		case TEE_ALG_AES_ECB_NOPAD:
		case TEE_ALG_DES_ECB_NOPAD:
		case TEE_ALG_DES3_ECB_NOPAD:
		case TEE_ALG_AES_CBC_NOPAD:
		case TEE_ALG_DES_CBC_NOPAD:
		case TEE_ALG_DES3_CBC_NOPAD:
			return TEE_ERROR_BAD_PARAMETERS;

		case TEE_ALG_AES_CTR:
		case TEE_ALG_AES_XTS:
		case TEE_ALG_AES_CTS:
			/*
			 * These modes doesn't require padding for the last
			 * block.
			 *
			 * This isn't entirely true, both XTS and CTS can only
			 * encrypt minimum one block and also they need at least
			 * one complete block in the last update to finish the
			 * encryption. The algorithms are supposed to detect
			 * that, we're only making sure that all data fed up to
			 * that point consists of complete blocks.
			 */
			break;

		default:
			return TEE_ERROR_NOT_SUPPORTED;
		}
	}

	switch (algo) {
	case TEE_ALG_AES_ECB_NOPAD:
	case TEE_ALG_DES_ECB_NOPAD:
	case TEE_ALG_DES3_ECB_NOPAD:
		if (mode == TEE_MODE_ENCRYPT)
		    ltc_res = ecb_encrypt(data, dst, len, (symmetric_ECB *)ctx);
		else
		    ltc_res = ecb_decrypt(data, dst, len, (symmetric_ECB *)ctx);
		break;

	case TEE_ALG_AES_CBC_NOPAD:
	case TEE_ALG_DES_CBC_NOPAD:
	case TEE_ALG_DES3_CBC_NOPAD:
		if (mode == TEE_MODE_ENCRYPT)
		    ltc_res = cbc_encrypt(data, dst, len, (symmetric_CBC *)ctx);
		else
		    ltc_res = cbc_decrypt(data, dst, len, (symmetric_CBC *)ctx);
		break;

	case TEE_ALG_AES_CTR:
		if (mode == TEE_MODE_ENCRYPT)
		    ltc_res = ctr_encrypt(data, dst, len, (symmetric_CTR *)ctx);
		else
		    ltc_res = ctr_decrypt(data, dst, len, (symmetric_CTR *)ctx);
		break;

	case TEE_ALG_AES_XTS:
		return TEE_ERROR_NOT_SUPPORTED;
/*
if (mode == TEE_MODE_ENCRYPT) {
	ltc_res = xts_encrypt(data, dst, len, (symmetric_xts *)ctx);
} else {
	ltc_res = xts_decrypt(data, dst, len, (symmetric_xts *)ctx);
}
*/
		break;

	case TEE_ALG_AES_CTS:
		/*
		 * From http://en.wikipedia.org/wiki/Ciphertext_stealing
		 * CBC ciphertext stealing encryption using a standard
		 * CBC interface:
		 *	1. Pad the last partial plaintext block with 0.
		 *	2. Encrypt the whole padded plaintext using the
		 *	   standard CBC mode.
		 *	3. Swap the last two ciphertext blocks.
		 *	4. Truncate the ciphertext to the length of the
		 *	   original plaintext.
		 *
		 * CBC ciphertext stealing decryption using a standard
		 * CBC interface
		 *	1. Dn = Decrypt (K, Cn-1). Decrypt the second to last
		 *	   ciphertext block.
		 *	2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the
		 *	   nearest multiple of the block size using the last
		 *	   B-M bits of block cipher decryption of the
		 *	   second-to-last ciphertext block.
		 *	3. Swap the last two ciphertext blocks.
		 *	4. Decrypt the (modified) ciphertext using the standard
		 *	   CBC mode.
		 *	5. Truncate the plaintext to the length of the original
		 *	   ciphertext.
		 */
		cts = (struct symmetric_CTS *)ctx;
		if (!last_block)
			return tee_cipher_update(
				&cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode,
				last_block, data, len, dst);

		/* Compute the last block length and check constraints */
		if (block_size > 64)
			return TEE_ERROR_BAD_STATE;
		nb_blocks = ((len + block_size - 1) / block_size);
		if (nb_blocks < 2)
			return TEE_ERROR_BAD_STATE;
		len_last_block = len % block_size;
		if (len_last_block == 0)
			len_last_block = block_size;

		if (mode == TEE_MODE_ENCRYPT) {
			memcpy(tmp_block,
			       data + ((nb_blocks - 1) * block_size),
			       len_last_block);
			memset(tmp_block + len_last_block,
			       0,
			       block_size - len_last_block);

			res = tee_cipher_update(
				&cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0,
				data, (nb_blocks - 1) * block_size, dst);
			if (res != TEE_SUCCESS)
				return res;

			memcpy(dst + (nb_blocks - 1) * block_size,
			       dst + (nb_blocks - 2) * block_size,
			       len_last_block);

			res = tee_cipher_update(
				&cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0,
				tmp_block,
				block_size,
				dst + (nb_blocks - 2) * block_size);
			if (res != TEE_SUCCESS)
				return res;
		} else {
			/* 1. Decrypt the second to last ciphertext block */
			res = tee_cipher_update(
				&cts->ecb, TEE_ALG_AES_ECB_NOPAD, mode, 0,
				data + (nb_blocks - 2) * block_size,
				block_size,
				tmp2_block);
			if (res != TEE_SUCCESS)
				return res;

			/* 2. Cn = Cn || Tail (Dn, B-M) */
			memcpy(tmp_block,
			       data + ((nb_blocks - 1) * block_size),
			       len_last_block);
			memcpy(tmp_block + len_last_block,
			       tmp2_block + len_last_block,
			       block_size - len_last_block);

			/* 3. Swap the last two ciphertext blocks */
			/* done by passing the correct buffers in step 4. */

			/* 4. Decrypt the (modified) ciphertext */
			if (nb_blocks > 2) {
				res = tee_cipher_update(
					&cts->cbc, TEE_ALG_AES_CBC_NOPAD,
					mode, 0,
					data,
					(nb_blocks - 2) * block_size,
					dst);
				if (res != TEE_SUCCESS)
					return res;
			}

			res = tee_cipher_update(
				&cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0,
				tmp_block,
				block_size,
				dst + ((nb_blocks - 2) * block_size));
			if (res != TEE_SUCCESS)
				return res;

			res = tee_cipher_update(
				&cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0,
				data + ((nb_blocks - 2) * block_size),
				block_size,
				tmp_block);
			if (res != TEE_SUCCESS)
				return res;

			/* 5. Truncate the plaintext */
			memcpy(dst + (nb_blocks - 1) * block_size,
			       tmp_block,
			       len_last_block);
			break;
		}
		break;

	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}

	if (ltc_res == CRYPT_OK)
		return TEE_SUCCESS;
	else
		return TEE_ERROR_BAD_STATE;
}