diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index f164ba69d2a5..4cb2ea857ea8 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -586,41 +586,55 @@ bool bt_crypto_s1(struct bt_crypto *crypto, const uint8_t k[16],
 	return bt_crypto_e(crypto, k, res, res);
 }
 
-static bool aes_cmac(struct bt_crypto *crypto, const uint8_t key[16],
+static bool aes_cmac_be(struct bt_crypto *crypto, const uint8_t key[16],
 			const uint8_t *msg, size_t msg_len, uint8_t res[16])
 {
-	uint8_t key_msb[16], out[16], msg_msb[CMAC_MSG_MAX];
 	ssize_t len;
 	int fd;
 
 	if (msg_len > CMAC_MSG_MAX)
 		return false;
 
-	swap_buf(key, key_msb, 16);
-	fd = alg_new(crypto->cmac_aes, key_msb, 16);
+	fd = alg_new(crypto->cmac_aes, key, 16);
 	if (fd < 0)
 		return false;
 
-	swap_buf(msg, msg_msb, msg_len);
-	len = send(fd, msg_msb, msg_len, 0);
+	len = send(fd, msg, msg_len, 0);
 	if (len < 0) {
 		close(fd);
 		return false;
 	}
 
-	len = read(fd, out, 16);
+	len = read(fd, res, 16);
 	if (len < 0) {
 		close(fd);
 		return false;
 	}
 
-	swap_buf(out, res, 16);
-
 	close(fd);
 
 	return true;
 }
 
+static bool aes_cmac(struct bt_crypto *crypto, const uint8_t key[16],
+			const uint8_t *msg, size_t msg_len, uint8_t res[16])
+{
+	uint8_t key_msb[16], out[16], msg_msb[CMAC_MSG_MAX];
+
+	if (msg_len > CMAC_MSG_MAX)
+		return false;
+
+	swap_buf(key, key_msb, 16);
+	swap_buf(msg, msg_msb, msg_len);
+
+	if (!aes_cmac_be(crypto, key_msb, msg_msb, msg_len, out))
+		return false;
+
+	swap_buf(out, res, 16);
+
+	return true;
+}
+
 bool bt_crypto_f4(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32],
 				uint8_t x[16], uint8_t z, uint8_t res[16])
 {
@@ -773,3 +787,142 @@ bool bt_crypto_sih(struct bt_crypto *crypto, const uint8_t k[16],
 {
 	return bt_crypto_ah(crypto, k, r, hash);
 }
+
+static bool aes_cmac_zero(struct bt_crypto *crypto, const uint8_t *msg,
+					size_t msg_len, uint8_t res[16])
+{
+	const uint8_t zero[16] = {};
+
+	return aes_cmac_be(crypto, zero, msg, msg_len, res);
+}
+
+/* The inputs to function s1 are:
+ *
+ *   M is a non-zero length octet array or ASCII encoded string
+ *
+ * If M is an ASCII encoded string, M shall be converted into an integer number
+ * by replacing each string character with its ASCII code preserving the order.
+ * For example, if M is the string “CSIS”, M is converted into the integer
+ * number: 0x4353 4953.
+ *
+ * ZERO is the 128-bit value:
+ *
+ *   0x0000 0000 0000 0000 0000 0000 0000 0000
+ *
+ * The output of the salt generation function s1 shall be calculated as follows:
+ *
+ *   s1(M)=AES‐CMACZERO(M)
+ *
+ * Where AES-CMACZERO is the CMAC function defined in Section 4.2.
+ */
+static bool sef_s1(struct bt_crypto *crypto, const uint8_t *m,
+					size_t m_len, uint8_t res[16])
+{
+	/* s1(M)=AES‐CMACZERO(M) */
+	return aes_cmac_zero(crypto, m, m_len, res);
+}
+
+/* The key derivation function k1 is used to derive a key. The derived key is
+ * used to encrypt and decrypt the value of the Set Identity Resolving Key
+ * characteristic (see Section 5.1).
+ *
+ * The definition of this key generation function uses the MAC function
+ * AES-CMACT with a 128-bit key T.
+ *
+ * The inputs to function k1 are:
+ *
+ *   N is 0 or more octets
+ *
+ *   SALT is 128 bits
+ *
+ *   P is 0 or more octets
+ *
+ * The key (T) shall be computed as follows:
+ *
+ *   T=AES‐CMACSALT(N)
+ *
+ * Where AES-CMACSALT is the CMAC function defined in Section 4.2.
+ *
+ * The output of the key generation function k1 shall be calculated as follows:
+ *
+ *   k1(N, SALT, P)=AES‐CMACT(P)
+ *
+ * Where AES-CMACT is the CMAC function defined in Section 4.2.
+ */
+static bool sef_k1(struct bt_crypto *crypto, const uint8_t n[16],
+				uint8_t salt[16], const uint8_t *p,
+				size_t p_len, uint8_t res[16])
+{
+	uint8_t res1[16];
+
+	/* T=AES‐CMACSALT(N) */
+	if (!aes_cmac_be(crypto, salt, n, 16, res1))
+		return false;
+
+	/* k1(N, SALT, P)=AES‐CMACT(P) */
+	return aes_cmac_be(crypto, res1, p, p_len, res);
+}
+
+/*
+ * SIRK encryption function sef
+ *
+ * The SIRK encryption function sef shall be used by the server to encrypt the
+ * SIRK with a key K. The value of K depends on the transport on which the Set
+ * Identity Resolving Key characteristic is read or notified.
+ *
+ * If the Set Identity Resolving Key characteristic is read or notified on the
+ * Basic Rate/Enhanced Data Rate (BR/EDR) transport, K shall be equal to the
+ * Link Key shared by the server and the client.
+ *
+ *   K=LinkKey
+ *
+ * If the Set Identity Resolving Key characteristic is read or notified on the
+ * Bluetooth Low Energy (LE) transport, K shall be equal to the LTK shared by
+ * the server and client. That is,
+ *
+ *   K=LTK
+ *
+ * The inputs to the function sef are:
+ *
+ *   K is the key defined above in this section
+ *
+ *   SIRK is the value of the SIRK to be encrypted
+ *
+ * The output of the SIRK encryption function sef is as follows:
+ *
+ *   sef(K, SIRK)=k1(K, s1(“SIRKenc”), “csis”)^SIRK
+ *
+ * Where ^ is the bitwise exclusive or operation.
+ */
+bool bt_crypto_sef(struct bt_crypto *crypto, const uint8_t k[16],
+			const uint8_t sirk[16], uint8_t out[16])
+{
+	const uint8_t m[] = {'S', 'I', 'R', 'K', 'e', 'n', 'c'};
+	const uint8_t p[] = {'c', 's', 'i', 's'};
+	uint8_t k_msb[16];
+	uint8_t salt[16];
+	uint8_t res_msb[16];
+	uint8_t res[16];
+
+	if (!crypto)
+		return false;
+
+	/* salt = s1(“SIRKenc”) */
+	if (!sef_s1(crypto, m, sizeof(m), salt))
+		return false;
+
+	/* Convert K to MSB/BE format */
+	swap_buf(k, k_msb, 16);
+
+	/* res_msb = k1(K, salt, “csis”) */
+	if (!sef_k1(crypto, k_msb, salt, p, sizeof(p), res_msb))
+		return false;
+
+	/* Convert back to LSB/LE format */
+	swap_buf(res_msb, res, 16);
+
+	/* res^SIRK */
+	u128_xor(res, sirk, out);
+
+	return true;
+}
diff --git a/src/shared/crypto.h b/src/shared/crypto.h
index fca52e38e5e2..fc1ba0c4feeb 100644
--- a/src/shared/crypto.h
+++ b/src/shared/crypto.h
@@ -53,5 +53,7 @@ bool bt_crypto_verify_att_sign(struct bt_crypto *crypto, const uint8_t key[16],
 				const uint8_t *pdu, uint16_t pdu_len);
 bool bt_crypto_gatt_hash(struct bt_crypto *crypto, struct iovec *iov,
 				size_t iov_len, uint8_t res[16]);
+bool bt_crypto_sef(struct bt_crypto *crypto, const uint8_t k[16],
+			const uint8_t sirk[16], uint8_t out[16]);
 bool bt_crypto_sih(struct bt_crypto *crypto, const uint8_t k[16],
 					const uint8_t r[3], uint8_t hash[3]);
