test: Bluetooth: tester: Add support for EAD peripheral

    Added three functions to support the EAD peripheral:
    - Setting and storing key materials for EAD
    - Encrypting data for EAD advertisements
    - Decrypting data from EAD advertisements

Signed-off-by: Petri Pitkanen <petri.pitkanen@silabs.com>
diff --git a/tests/bluetooth/tester/src/btp/btp_gap.h b/tests/bluetooth/tester/src/btp/btp_gap.h
index 924859c..7b6bc23 100644
--- a/tests/bluetooth/tester/src/btp/btp_gap.h
+++ b/tests/bluetooth/tester/src/btp/btp_gap.h
@@ -393,6 +393,37 @@
 	uint16_t rpa_timeout;
 } __packed;
 
+#define BTP_GAP_EAD_SET_KEY_MATERIAL_KEY_SIZE 16
+#define BTP_GAP_EAD_SET_KEY_MATERIAL_IV_SIZE  8
+#define BTP_GAP_EAD_MAX_DATA_LEN              255
+#define BTP_GAP_EAD_SET_KEY_MATERIAL          0x31
+struct btp_gap_ead_set_key_material_cmd {
+	uint8_t session_key[BTP_GAP_EAD_SET_KEY_MATERIAL_KEY_SIZE];
+	uint8_t initialization_vector[BTP_GAP_EAD_SET_KEY_MATERIAL_IV_SIZE];
+} __packed;
+
+#define BTP_GAP_EAD_ENCRYPT_ADV_DATA 0x32
+struct btp_gap_ead_encrypt_adv_data_cmd {
+	uint8_t adv_data_len;
+	uint8_t adv_data[];
+} __packed;
+
+struct btp_gap_ead_encrypt_adv_data_rp {
+	uint8_t encrypted_data_len;
+	uint8_t encrypted_data[];
+} __packed;
+
+#define BTP_GAP_EAD_DECRYPT_ADV_DATA 0x33
+struct btp_gap_ead_decrypt_adv_data_cmd {
+	uint8_t encrypted_data_len;
+	uint8_t encrypted_data[];
+} __packed;
+
+struct btp_gap_decrypt_ead_adv_data_rp {
+	uint8_t decrypted_data_len;
+	uint8_t decrypted_data[];
+} __packed;
+
 /* events */
 #define BTP_GAP_EV_NEW_SETTINGS			0x80
 struct btp_gap_new_settings_ev {
diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c
index 1344933..86892d4 100644
--- a/tests/bluetooth/tester/src/btp_gap.c
+++ b/tests/bluetooth/tester/src/btp_gap.c
@@ -20,6 +20,7 @@
 #include <zephyr/bluetooth/gap.h>
 #include <zephyr/bluetooth/hci_types.h>
 #include <zephyr/bluetooth/uuid.h>
+#include <zephyr/bluetooth/ead.h>
 #include <zephyr/logging/log.h>
 #include <zephyr/sys/atomic.h>
 #include <zephyr/sys/util.h>
@@ -2831,6 +2832,85 @@
 }
 #endif /* defined(CONFIG_BT_ISO_BROADCASTER) */
 
+#if defined(CONFIG_BT_EAD)
+static struct ead_key_materials_s {
+	uint8_t session_key[BTP_GAP_EAD_SET_KEY_MATERIAL_KEY_SIZE];
+	uint8_t initialization_vector[BTP_GAP_EAD_SET_KEY_MATERIAL_IV_SIZE];
+} ead_key_materials;
+
+/*
+ * This command to be used by both central and peripheral.
+ * central side should get key material by reading them from the peripheral
+ * gatt database. Obviously key materials can be shared OOB as well.
+ */
+static uint8_t ead_set_key_material(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
+{
+	const struct btp_gap_ead_set_key_material_cmd *cp = cmd;
+
+	(void)memcpy(ead_key_materials.session_key, cp->session_key,
+		     sizeof(ead_key_materials.session_key));
+	(void)memcpy(ead_key_materials.initialization_vector, cp->initialization_vector,
+		     sizeof(ead_key_materials.initialization_vector));
+
+	return BTP_STATUS_SUCCESS;
+}
+
+static uint8_t ead_encrypt_data(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
+{
+	const struct btp_gap_ead_encrypt_adv_data_cmd *cp = cmd;
+	struct btp_gap_ead_encrypt_adv_data_rp *rp = rsp;
+	int err;
+	size_t encrypted_size;
+
+	if ((cmd_len < sizeof(*cp)) || (cmd_len != sizeof(*cp) + cp->adv_data_len)) {
+		return BTP_STATUS_FAILED;
+	}
+
+	encrypted_size = BT_EAD_ENCRYPTED_PAYLOAD_SIZE(cp->adv_data_len);
+	if (encrypted_size > BTP_GAP_EAD_MAX_DATA_LEN) {
+		LOG_ERR("Plain text data length exceeds max supported");
+		return BTP_STATUS_FAILED;
+	}
+
+	err = bt_ead_encrypt(ead_key_materials.session_key, ead_key_materials.initialization_vector,
+			     cp->adv_data, cp->adv_data_len, rp->encrypted_data);
+
+	if (err < 0) {
+		LOG_ERR("Failed to encrypt data: %d", err);
+		return BTP_STATUS_FAILED;
+	}
+
+	rp->encrypted_data_len = encrypted_size;
+	*rsp_len = sizeof(*rp) + rp->encrypted_data_len;
+
+	return BTP_STATUS_SUCCESS;
+}
+
+static uint8_t ead_decrypt_data(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
+{
+	const struct btp_gap_ead_decrypt_adv_data_cmd *cp = cmd;
+	struct btp_gap_decrypt_ead_adv_data_rp *rp = rsp;
+	int err;
+
+	if ((cmd_len < sizeof(*cp)) || (cmd_len != sizeof(*cp) + cp->encrypted_data_len)) {
+		return BTP_STATUS_FAILED;
+	}
+
+	err = bt_ead_decrypt(ead_key_materials.session_key, ead_key_materials.initialization_vector,
+			     cp->encrypted_data, cp->encrypted_data_len, rp->decrypted_data);
+
+	if (err < 0) {
+		LOG_ERR("Failed to decrypt data: %d", err);
+		return BTP_STATUS_FAILED;
+	}
+
+	rp->decrypted_data_len = BT_EAD_DECRYPTED_PAYLOAD_SIZE(cp->encrypted_data_len);
+	*rsp_len = sizeof(*rp) + rp->decrypted_data_len;
+
+	return BTP_STATUS_SUCCESS;
+}
+#endif /* defined(CONFIG_BT_EAD) */
+
 static const struct btp_handler handlers[] = {
 	{
 		.opcode = BTP_GAP_READ_SUPPORTED_COMMANDS,
@@ -3045,6 +3125,23 @@
 		.func = bis_broadcast,
 	},
 #endif /* defined(CONFIG_BT_ISO_BROADCASTER) */
+#if defined(CONFIG_BT_EAD)
+	{
+		.opcode = BTP_GAP_EAD_SET_KEY_MATERIAL,
+		.expect_len = sizeof(struct btp_gap_ead_set_key_material_cmd),
+		.func = ead_set_key_material,
+	},
+	{
+		.opcode = BTP_GAP_EAD_ENCRYPT_ADV_DATA,
+		.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
+		.func = ead_encrypt_data,
+	},
+	{
+		.opcode = BTP_GAP_EAD_DECRYPT_ADV_DATA,
+		.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
+		.func = ead_decrypt_data,
+	},
+#endif /* defined(CONFIG_BT_EAD) */
 };
 
 uint8_t tester_init_gap(void)