From ddae9499b123f58ad6b70f20ee65ce28919889a2 Mon Sep 17 00:00:00 2001
From: Michael Rupp <Michael.Rupp@silabs.com>
Date: Mon, 13 May 2024 16:24:40 +0000
Subject: [PATCH 01/10] Pull request #1836: Cherry multi ota

Merge in WMN_TOOLS/matter from cherry-multi-ota to silabs_slc_1.3

Squashed commit of the following:

commit 4320bb46571658bc44fb82345348265def394991
Author: Michael Rupp <michael.rupp@silabs.com>
Date:   Fri May 10 14:26:07 2024 -0400

    remove some unwanted diffs in provision files

commit be160931dc600de7e7ead378b70d6a43c3945e46
Author: Michael Rupp <michael.rupp@silabs.com>
Date:   Fri May 10 14:24:25 2024 -0400

    revert changes to generator.project.mak

commit 14b6605887166e6d5284a61feb2bf407d850bdcf
Author: Michael Rupp <michael.rupp@silabs.com>
Date:   Fri May 10 13:06:12 2024 -0400

    revert NVM key changes and script changes

... and 8 more commits
---
 .../provision/ProvisionStorageDefault.cpp     |   1 +
 .../silabs/factory_data_generator/README.md   |  56 ++++++
 .../silabs/factory_data_generator/custom.py   | 105 +++++++++++
 .../silabs/factory_data_generator/default.py  | 131 +++++++++++++
 scripts/tools/silabs/ota/README.md            |  15 +-
 .../binaries/ext_flash_ota_entry_example.bin  | Bin 0 -> 7056 bytes
 .../examples/ota_custom_entries_example.json  |  67 +++++++
 .../examples/ota_custom_entries_example2.json |  88 +++++++++
 .../tools/silabs/ota/ota_multi_image_tool.py  |   9 +-
 scripts/tools/silabs/ota/requirements.txt     |   1 +
 src/platform/silabs/efr32/BUILD.gn            |  21 ++-
 .../silabs/efr32/efr32-psa-crypto-config.h    |   5 +
 .../silabs/multi-ota/OTACustomProcessor.cpp   |  94 ++++++++++
 .../silabs/multi-ota/OTACustomProcessor.h     |  56 ++++++
 .../multi-ota/OTAFactoryDataProcessor.cpp     | 172 ++++++++++++++++++
 .../multi-ota/OTAFactoryDataProcessor.h       |  82 +++++++++
 .../{efr32 => }/OTAFirmwareProcessor.cpp      |  37 +++-
 .../{efr32 => }/OTAFirmwareProcessor.h        |   0
 .../silabs/multi-ota/{efr32 => }/OTAHooks.cpp |  25 ++-
 .../multi-ota/OTAMultiImageProcessorImpl.cpp  |   3 -
 .../silabs/multi-ota/OTATlvProcessor.cpp      |  70 +------
 .../silabs/multi-ota/OTATlvProcessor.h        |  10 +
 .../silabs/multi-ota/OtaTlvEncryptionKey.cpp  | 132 ++++++++++++++
 .../silabs/multi-ota/OtaTlvEncryptionKey.h    |  35 ++++
 third_party/silabs/efr32_sdk.gni              |  10 +
 25 files changed, 1138 insertions(+), 87 deletions(-)
 create mode 100644 scripts/tools/silabs/factory_data_generator/README.md
 create mode 100644 scripts/tools/silabs/factory_data_generator/custom.py
 create mode 100644 scripts/tools/silabs/factory_data_generator/default.py
 create mode 100755 scripts/tools/silabs/ota/examples/binaries/ext_flash_ota_entry_example.bin
 create mode 100644 scripts/tools/silabs/ota/examples/ota_custom_entries_example.json
 create mode 100644 scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json
 create mode 100644 scripts/tools/silabs/ota/requirements.txt
 create mode 100644 src/platform/silabs/multi-ota/OTACustomProcessor.cpp
 create mode 100644 src/platform/silabs/multi-ota/OTACustomProcessor.h
 create mode 100644 src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
 create mode 100644 src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
 rename src/platform/silabs/multi-ota/{efr32 => }/OTAFirmwareProcessor.cpp (84%)
 rename src/platform/silabs/multi-ota/{efr32 => }/OTAFirmwareProcessor.h (100%)
 rename src/platform/silabs/multi-ota/{efr32 => }/OTAHooks.cpp (53%)
 create mode 100644 src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
 create mode 100644 src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h

diff --git a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
index 09f103592d2470..410f43caaf341b 100644
--- a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
+++ b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
@@ -16,6 +16,7 @@
  */
 #include "AttestationKey.h"
 #include "ProvisionStorage.h"
+#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #include <credentials/examples/DeviceAttestationCredsExample.h>
 #include <lib/support/BytesToHex.h>
 #include <lib/support/CHIPMemString.h>
diff --git a/scripts/tools/silabs/factory_data_generator/README.md b/scripts/tools/silabs/factory_data_generator/README.md
new file mode 100644
index 00000000000000..c75c52f91d0333
--- /dev/null
+++ b/scripts/tools/silabs/factory_data_generator/README.md
@@ -0,0 +1,56 @@
+# Silabs Factory Data Generator
+
+## Tool implementation
+
+The tool comprises of two files: `default.py`, `custom.py`
+
+### `default.py`
+
+Defines the base `InputArgument` class and its derived classes that will be
+referenced as **default classes**.
+
+`InputArgument` offers an abstract interface in the form of three methods:
+`key()`, `length()`, `encode()`, that will be used to generate the `(K, L, V)`
+tuple through the public `output()` method. Each custom class should implement
+the abstract interface, if its direct parent does not offer a relevant
+implementation.
+
+### `custom.py`
+
+Defines classes for each argument that should generate data in the output binary
+(will be referenced as **custom classes**). Please note that each new class
+should derive from a default class, not from `InputArgument` directly.
+
+### How to add a new argument
+
+Example of defining a new argument class in `custom.py`:
+
+```
+class FooArgument(BarArgument):
+    def __init__(self, arg):
+        super().__init__(arg)
+
+    def key(self):
+        return <unique key identifier>
+
+    def length(self):
+        return <actual length of data>
+
+    def encode(self):
+        return <data as encoded bytes>
+
+    def custom_function(self):
+        pass
+```
+
+where `BarArgument` is one of the **default classes**. Please note that a user
+can define additional methods if needed (e.g. `custom_function`; also see
+`generate_private_key` from `DacPKey` class).
+
+Then use this class in `generate.py` to create a `FooArgument` object from an
+option:
+
+```
+parser.add_argument("--foo", required=True, type=FooArgument,
+                    help="[int | hex] Foo argument.")
+```
diff --git a/scripts/tools/silabs/factory_data_generator/custom.py b/scripts/tools/silabs/factory_data_generator/custom.py
new file mode 100644
index 00000000000000..00ee76178b51a0
--- /dev/null
+++ b/scripts/tools/silabs/factory_data_generator/custom.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+#
+#    Copyright (c) 2022 Project CHIP Authors
+#    All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+
+'''This file should contain custom classes derived any class from default.py.
+
+Each class implemented here should describe an input parameter and should
+implement the InputArgument abstract interface, if its base class does not
+already offer an implementation or if there is a need of a custom behavior.
+
+Example of defining a new argument class:
+
+    class FooArgument(IntArgument):
+        def __init__(self, arg):
+            super().__init__(arg)
+
+        def key(self):
+            return <unique key identifier>
+
+        def length(self):
+            return <actual length of data>
+
+        def encode(self):
+            return <data as encoded bytes>
+
+        def custom_function(self):
+            pass
+
+Then use this class in generate.py to create a FooArgument object from an
+option:
+
+    parser.add_argument("--foo", required=True, type=FooArgument,
+                        help="[int | hex] Foo argument.")
+'''
+
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives.serialization import load_der_private_key
+from default import Base64Argument, FileArgument, IntArgument, StrArgument
+
+class DacPKey(FileArgument):
+
+    def __init__(self, arg):
+        super().__init__(arg)
+        self.private_key = None
+
+    def key(self):
+        return 1
+
+    def length(self):
+        assert (self.private_key is not None)
+        return len(self.private_key)
+
+    def encode(self):
+        assert (self.private_key is not None)
+        return self.private_key
+
+    def generate_private_key(self, password, use_sss_blob=True):
+        if use_sss_blob:
+            self.private_key = self.val
+        else:
+            keys = load_der_private_key(self.val, password, backend=default_backend())
+            self.private_key = keys.private_numbers().private_value.to_bytes(
+                32, byteorder='big'
+            )
+
+
+class DacCert(FileArgument):
+
+    def __init__(self, arg):
+        super().__init__(arg)
+
+    def key(self):
+        return 2
+
+
+class PaiCert(FileArgument):
+
+    def __init__(self, arg):
+        super().__init__(arg)
+
+    def key(self):
+        return 3
+
+
+class CertDeclaration(FileArgument):
+
+    def __init__(self, arg):
+        super().__init__(arg)
+
+    def key(self):
+        return 4
diff --git a/scripts/tools/silabs/factory_data_generator/default.py b/scripts/tools/silabs/factory_data_generator/default.py
new file mode 100644
index 00000000000000..13dc0866aaed40
--- /dev/null
+++ b/scripts/tools/silabs/factory_data_generator/default.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+#
+#    Copyright (c) 2022 Project CHIP Authors
+#    All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+'''This file should contain default argument classes.
+
+Base class is InputArgument. It defines the abstract interface to be
+implemented and offers a way to compute a KLV value through output().
+Other classes that derive InputArgument directly will be referenced
+as default classes throughout the docstrings.
+
+The default classes should not be used to instantiate arguments.
+If one wants to add another argument, a custom class should be derived
+from one of the default classes.
+'''
+
+import base64
+import logging
+
+
+class InputArgument:
+    '''Base class for any input argument that will be added to KLV.
+
+    The user will define its arguments as instances of InputArgument
+    by setting the "type" attribute of ArgumentParser add_argument to
+    an instance of a derived class. This means that all derived classes
+    must accept an additional "arg" parameter in the constructor. In the
+    end, the list of arguments will be parsed into objects derived from
+    InputArgument (or default derived classes), which decouples the object
+    creation from its processing.
+
+    Abstract methods:
+        key: Should be overwritten by final classes to return a "magic number".
+        length: Can be overwritten by default classes to specify a default value
+                (e.g. int arguments with a default length value of 4); can also
+                be overwritten by final classes to specify a custom value for a
+                certain argument.
+        encode: Should be overwritten to generate the correct bytes array from
+                its internal value.
+
+    Main usage is to iterate over an iterable entity of InputArguments and call
+    the output() method to generate the (K, L, V) tuple. Note that the output()
+    method should not be implemented, since its a common functionality across
+    all InputArgument classes.
+    '''
+
+    def __init__(self):
+        self.val = None
+
+    def key(self):
+        logging.error("key() should be implemented in derived classes.")
+
+    def length(self):
+        logging.error("length() should be implemented in derived classes.")
+
+    def encode(self):
+        logging.error("encode() should be implemented in derived classes.")
+
+    def output(self):
+        out = (self.key(), self.length(), self.encode())
+        logging.info("'{}' length: {}".format(type(self).__name__, self.length()))
+        return out
+
+
+class IntArgument(InputArgument):
+
+    def __init__(self, arg):
+        super().__init__()
+        self.val = int(arg, 0)
+
+    def length(self):
+        return 4
+
+    def encode(self):
+        return self.val.to_bytes(self.length(), "little")
+
+
+class Base64Argument(InputArgument):
+
+    def __init__(self, arg):
+        super().__init__()
+        self.val = base64.b64decode(arg)
+
+    def length(self):
+        return len(self.encode())
+
+    def encode(self):
+        return base64.b64encode(self.val)
+
+
+class StrArgument(InputArgument):
+
+    def __init__(self, arg):
+        super().__init__()
+        self.val = str(arg)
+
+    def length(self):
+        return len(self.encode())
+
+    def encode(self):
+        return str.encode(self.val)
+
+    def max_length(self):
+        return 32
+
+
+class FileArgument(InputArgument):
+
+    def __init__(self, arg):
+        super().__init__()
+        with open(arg, "rb") as _file:
+            self.val = _file.read()
+
+    def length(self):
+        return len(self.val)
+
+    def encode(self):
+        return self.val
diff --git a/scripts/tools/silabs/ota/README.md b/scripts/tools/silabs/ota/README.md
index d0c1bd39e068cd..0629d8650c1e8a 100644
--- a/scripts/tools/silabs/ota/README.md
+++ b/scripts/tools/silabs/ota/README.md
@@ -25,8 +25,7 @@ python3 ./scripts/tools/silabs/ota/ota_multi_image_tool.py create -v 0xDEAD -p 0
 ```
 
 followed by \*_custom options_- and a positional argument (should be last) that
-specifies the output file. Please see the `create_ota_images.sh` for some
-reference commands.
+specifies the output file.
 
 The list of **custom options**:
 
@@ -38,12 +37,6 @@ The list of **custom options**:
 --app-version-str  --> Application version string. Same as above.
 --app-build-date   --> Application build date. Same as above.
 
-# SSBL options
---bl-input-file    --> Path to the SSBL binary.
---bl-version       --> SSBL version.
---bl-version-str   --> SSBL version string.
---bl-build-date    --> SSBL build date.
-
 # Factory data options
 --factory-data     --> If set, enables the generation of factory data.
 --cert_declaration --> Certification Declaration.
@@ -51,6 +44,10 @@ The list of **custom options**:
 --dac_key          --> DAC private key.
 --pai_cert         --> PAI certificate.
 
+# Encryption options
+--enc_enable       --> Enable ota encryption
+--input_ota_key    --> 16 Byte AES key
+
 # Custom TLV options
 --json             --> Path to a JSON file following ota_payload.schema
 ```
@@ -67,5 +64,5 @@ processing.
 When defining a custom processor, a user is able to also specify the custom
 format of the TLV by creating a JSON file based on the `ota_payload.schema`. The
 tool offers support for describing multiple TLV in the same JSON file. Please
-see the `examples/ota_max_entries_example.json` for a multi-app + SSBL example.
+see the `examples/ota_custom_entries_example.json` for a multi-binary example.
 Option `--json` must be used to specify the path to the JSON file.
diff --git a/scripts/tools/silabs/ota/examples/binaries/ext_flash_ota_entry_example.bin b/scripts/tools/silabs/ota/examples/binaries/ext_flash_ota_entry_example.bin
new file mode 100755
index 0000000000000000000000000000000000000000..5800a9860f70aae4d8f235a4371b31c6b77a498f
GIT binary patch
literal 7056
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
aOX=pJ+=kw7SL#0dc~SP73%^%zf&UFmw4W~k

literal 0
HcmV?d00001

diff --git a/scripts/tools/silabs/ota/examples/ota_custom_entries_example.json b/scripts/tools/silabs/ota/examples/ota_custom_entries_example.json
new file mode 100644
index 00000000000000..8f679a266da9bd
--- /dev/null
+++ b/scripts/tools/silabs/ota/examples/ota_custom_entries_example.json
@@ -0,0 +1,67 @@
+{
+    "inputs": [
+        {
+            "tag": 8,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1003
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        },
+        {
+            "tag": 9,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1004
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion2"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        },
+        {
+            "tag": 10,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1005
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion3"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        }
+    ]
+}
diff --git a/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json b/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json
new file mode 100644
index 00000000000000..e850c91b909726
--- /dev/null
+++ b/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json
@@ -0,0 +1,88 @@
+{
+    "inputs": [
+        {
+            "tag": 8,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1003
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        },
+        {
+            "tag": 9,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1004
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion2"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        },
+        {
+            "tag": 10,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1005
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion3"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        },
+        {
+            "tag": 11,
+            "descriptor": [
+                {
+                    "name": "binary_version",
+                    "length": 4,
+                    "value": 1006
+                },
+                {
+                    "name": "binary_version_str",
+                    "length": 64,
+                    "value": "TestVersion4"
+                },
+                {
+                    "name": "build_date",
+                    "length": 64,
+                    "value": "2024-03-25"
+                }
+            ],
+            "path": "./binaries/ext_flash_ota_entry_example.bin"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/scripts/tools/silabs/ota/ota_multi_image_tool.py b/scripts/tools/silabs/ota/ota_multi_image_tool.py
index 64715d784aeecd..cd7ac6dbe2d253 100755
--- a/scripts/tools/silabs/ota/ota_multi_image_tool.py
+++ b/scripts/tools/silabs/ota/ota_multi_image_tool.py
@@ -50,7 +50,6 @@
 from chip.tlv import TLVWriter  # noqa: E402 isort:skip
 from custom import CertDeclaration, DacCert, DacPKey, PaiCert  # noqa: E402 isort:skip
 from default import InputArgument  # noqa: E402 isort:skip
-from generate import set_logger  # noqa: E402 isort:skip
 
 OTA_APP_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_app_tlv.bin")
 OTA_BOOTLOADER_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_ssbl_tlv.bin")
@@ -64,6 +63,14 @@ class TAG:
     BOOTLOADER = 2
     FACTORY_DATA = 3
 
+def set_logger():
+    stdout_handler = logging.StreamHandler(stream=sys.stdout)
+    logging.basicConfig(
+        level=logging.DEBUG,
+        format='[%(levelname)s] %(message)s',
+        handlers=[stdout_handler]
+    )
+
 
 def write_to_temp(path: str, payload: bytearray):
     with open(path, "wb") as _handle:
diff --git a/scripts/tools/silabs/ota/requirements.txt b/scripts/tools/silabs/ota/requirements.txt
new file mode 100644
index 00000000000000..9d440c9c5b780b
--- /dev/null
+++ b/scripts/tools/silabs/ota/requirements.txt
@@ -0,0 +1 @@
+jsonschema>=3.2.0
diff --git a/src/platform/silabs/efr32/BUILD.gn b/src/platform/silabs/efr32/BUILD.gn
index 5d661886d54f21..ca65a25ff9944f 100644
--- a/src/platform/silabs/efr32/BUILD.gn
+++ b/src/platform/silabs/efr32/BUILD.gn
@@ -78,14 +78,29 @@ static_library("efr32") {
   }
 
   if (chip_enable_multi_ota_requestor) {
+    if(chip_enable_multi_ota_encryption) {
+      sources += [
+        "${silabs_platform_dir}/multi-ota/OtaTlvEncryptionKey.cpp",
+        "${silabs_platform_dir}/multi-ota/OtaTlvEncryptionKey.h",
+      ]
+    }
+
+  if (chip_enable_ota_custom_tlv_testing) {
+      sources += [
+        "${silabs_platform_dir}/multi-ota/OTACustomProcessor.cpp",
+        "${silabs_platform_dir}/multi-ota/OTACustomProcessor.h",
+      ]
+    }
     sources += [
       "${silabs_platform_dir}/multi-ota/OTAMultiImageProcessorImpl.cpp",
       "${silabs_platform_dir}/multi-ota/OTAMultiImageProcessorImpl.h",
+      "${silabs_platform_dir}/multi-ota/OTAFactoryDataProcessor.cpp",
+      "${silabs_platform_dir}/multi-ota/OTAFactoryDataProcessor.h",
       "${silabs_platform_dir}/multi-ota/OTATlvProcessor.cpp",
       "${silabs_platform_dir}/multi-ota/OTATlvProcessor.h",
-      "${silabs_platform_dir}/multi-ota/efr32/OTAFirmwareProcessor.cpp",
-      "${silabs_platform_dir}/multi-ota/efr32/OTAFirmwareProcessor.h",
-      "${silabs_platform_dir}/multi-ota/efr32/OTAHooks.cpp",
+      "${silabs_platform_dir}/multi-ota/OTAFirmwareProcessor.cpp",
+      "${silabs_platform_dir}/multi-ota/OTAFirmwareProcessor.h",
+      "${silabs_platform_dir}/multi-ota/OTAHooks.cpp",
     ]
   } else if (chip_enable_ota_requestor) {
     sources += [
diff --git a/src/platform/silabs/efr32/efr32-psa-crypto-config.h b/src/platform/silabs/efr32/efr32-psa-crypto-config.h
index b5564f88bd3258..b389431f85ec0b 100644
--- a/src/platform/silabs/efr32/efr32-psa-crypto-config.h
+++ b/src/platform/silabs/efr32/efr32-psa-crypto-config.h
@@ -30,5 +30,10 @@
 #define PSA_WANT_ALG_CBC_NO_PADDING
 #endif // SL_USE_COAP_CONFIG
 
+// Multi-chip OTA encryption processing
+#if OTA_ENCRYPTION_ENABLE
+#define PSA_WANT_ALG_CTR
+#endif // OTA_ENCRYPTION_ENABLE
+
 // Include Generated fies
 #include "psa_crypto_config.h"
diff --git a/src/platform/silabs/multi-ota/OTACustomProcessor.cpp b/src/platform/silabs/multi-ota/OTACustomProcessor.cpp
new file mode 100644
index 00000000000000..89c3cb133e3d46
--- /dev/null
+++ b/src/platform/silabs/multi-ota/OTACustomProcessor.cpp
@@ -0,0 +1,94 @@
+/*
+ *
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
+#include <platform/silabs/multi-ota/OTACustomProcessor.h>
+
+#include <app/clusters/ota-requestor/OTARequestorInterface.h>
+
+extern "C" {
+#include "btl_interface.h"
+#include "em_bus.h" // For CORE_CRITICAL_SECTION
+#if SL_WIFI
+#include "spi_multiplex.h"
+#endif // SL_WIFI
+}
+
+/// No error, operation OK
+#define SL_BOOTLOADER_OK 0L
+
+namespace chip {
+
+// Define static memebers
+uint8_t OTACustomProcessor::mSlotId                                                  = 0;
+uint32_t OTACustomProcessor::mWriteOffset                                            = 0;
+uint16_t OTACustomProcessor::writeBufOffset                                          = 0;
+uint8_t OTACustomProcessor::writeBuffer[kAlignmentBytes] __attribute__((aligned(4))) = { 0 };
+
+CHIP_ERROR OTACustomProcessor::Init()
+{
+    ReturnErrorCodeIf(mCallbackProcessDescriptor == nullptr, CHIP_OTA_PROCESSOR_CB_NOT_REGISTERED);
+    mAccumulator.Init(sizeof(Descriptor));
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTACustomProcessor::Clear()
+{
+    OTATlvProcessor::ClearInternal();
+    mAccumulator.Clear();
+    mDescriptorProcessed = false;
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTACustomProcessor::ProcessInternal(ByteSpan & block)
+{
+    if (!mDescriptorProcessed)
+    {
+        ReturnErrorOnFailure(ProcessDescriptor(block));
+    }
+
+    ChipLogError(SoftwareUpdate, "Reached Custom Processor");
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTACustomProcessor::ProcessDescriptor(ByteSpan & block)
+{
+    ReturnErrorOnFailure(mAccumulator.Accumulate(block));
+    ReturnErrorOnFailure(mCallbackProcessDescriptor(static_cast<void *>(mAccumulator.data())));
+
+    mDescriptorProcessed = true;
+    mAccumulator.Clear();
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTACustomProcessor::ApplyAction()
+{
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTACustomProcessor::FinalizeAction()
+{
+    return CHIP_NO_ERROR;
+}
+
+} // namespace chip
diff --git a/src/platform/silabs/multi-ota/OTACustomProcessor.h b/src/platform/silabs/multi-ota/OTACustomProcessor.h
new file mode 100644
index 00000000000000..67980911d29be7
--- /dev/null
+++ b/src/platform/silabs/multi-ota/OTACustomProcessor.h
@@ -0,0 +1,56 @@
+/*
+ *
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <lib/support/Span.h>
+#include <platform/silabs/multi-ota/OTATlvProcessor.h>
+
+namespace chip {
+
+class OTACustomProcessor : public OTATlvProcessor
+{
+public:
+    struct Descriptor
+    {
+        uint32_t version;
+        char versionString[kVersionStringSize];
+        char buildDate[kBuildDateSize];
+    };
+
+    CHIP_ERROR Init() override;
+    CHIP_ERROR Clear() override;
+    CHIP_ERROR ApplyAction() override;
+    CHIP_ERROR FinalizeAction() override;
+
+private:
+    CHIP_ERROR ProcessInternal(ByteSpan & block) override;
+    CHIP_ERROR ProcessDescriptor(ByteSpan & block);
+
+    OTADataAccumulator mAccumulator;
+    bool mDescriptorProcessed = false;
+    static constexpr size_t kAlignmentBytes = 64;
+    static uint32_t mWriteOffset; // End of last written block
+    static uint8_t mSlotId;       // Bootloader storage slot
+    // Bootloader storage API requires the buffer size to be a multiple of 4.
+    static uint8_t writeBuffer[kAlignmentBytes] __attribute__((aligned(4)));
+    // Offset indicates how far the write buffer has been filled
+    static uint16_t writeBufOffset;
+};
+
+} // namespace chip
diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
new file mode 100644
index 00000000000000..e89e9c027dc3b9
--- /dev/null
+++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
@@ -0,0 +1,172 @@
+/*
+ *
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <lib/core/TLV.h>
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <platform/silabs/multi-ota/OTAFactoryDataProcessor.h>
+
+namespace chip {
+
+using FactoryProvider     = DeviceLayer::Silabs::Provision::Storage;
+
+CHIP_ERROR OTAFactoryDataProcessor::Init()
+{
+    mAccumulator.Init(mLength);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::Clear()
+{
+    OTATlvProcessor::ClearInternal();
+    mAccumulator.Clear();
+    mPayload.Clear();
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::ProcessInternal(ByteSpan & block)
+{
+    CHIP_ERROR error = CHIP_NO_ERROR;
+
+    ReturnErrorOnFailure(mAccumulator.Accumulate(block));
+#if OTA_ENCRYPTION_ENABLE
+    MutableByteSpan mBlock = MutableByteSpan(mAccumulator.data(), mAccumulator.GetThreshold());
+    OTATlvProcessor::vOtaProcessInternalEncryption(mBlock);
+#endif
+    error = DecodeTlv();
+
+    if (error != CHIP_NO_ERROR)
+    {
+        // The factory data payload can contain a variable number of fields
+        // to be updated. CHIP_END_OF_TLV is returned if no more fields are
+        // found.
+        if (error == CHIP_END_OF_TLV)
+        {
+            return CHIP_NO_ERROR;
+        }
+
+        Clear();
+    }
+
+    return error;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::ApplyAction()
+{
+    CHIP_ERROR error           = CHIP_NO_ERROR;
+
+    SuccessOrExit(error = Update((uint8_t) FactoryTags::kDacKey, mPayload.mCertDacKey));
+    SuccessOrExit(error = Update((uint8_t) FactoryTags::kDacCert, mPayload.mCertDac));
+    SuccessOrExit(error = Update((uint8_t) FactoryTags::kPaiCert, mPayload.mCertPai));
+    SuccessOrExit(error = Update((uint8_t) FactoryTags::kCdCert, mPayload.mCertDeclaration));
+
+exit:
+    if (error != CHIP_NO_ERROR)
+    {
+        ChipLogError(SoftwareUpdate, "Failed to update factory data. Error: %s", ErrorStr(error));
+    }
+    else
+    {
+        ChipLogProgress(SoftwareUpdate, "Factory data update finished.");
+    }
+
+    return error;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::FinalizeAction()
+{
+    ChipLogProgress(SoftwareUpdate, "Finalize Action\n");
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::DecodeTlv()
+{
+    TLV::TLVReader tlvReader;
+    tlvReader.Init(mAccumulator.data(), mLength);
+    ReturnErrorOnFailure(tlvReader.Next(TLV::TLVType::kTLVType_Structure, TLV::AnonymousTag()));
+
+    TLV::TLVType outerType;
+    ReturnErrorOnFailure(tlvReader.EnterContainer(outerType));
+    ReturnErrorOnFailure(tlvReader.Next());
+
+    if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) FactoryTags::kDacKey))
+    {
+        ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertDacKey.Emplace()));
+        ReturnErrorOnFailure(tlvReader.Next());
+    }
+
+    if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) FactoryTags::kDacCert))
+    {
+        ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertDac.Emplace()));
+        ReturnErrorOnFailure(tlvReader.Next());
+    }
+
+    if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) FactoryTags::kPaiCert))
+    {
+        ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertPai.Emplace()));
+        ReturnErrorOnFailure(tlvReader.Next());
+    }
+
+    if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) FactoryTags::kCdCert))
+    {
+        ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertDeclaration.Emplace()));
+    }
+
+    ReturnErrorOnFailure(tlvReader.ExitContainer(outerType));
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::Update(uint8_t tag, Optional<ByteSpan> & optional)
+{
+    CHIP_ERROR error = CHIP_NO_ERROR;
+    if (optional.HasValue())
+    {
+        error = UpdateValue(tag, optional.Value());
+    }
+
+    return error;
+}
+
+CHIP_ERROR OTAFactoryDataProcessor::UpdateValue(uint8_t tag, ByteSpan & newValue)
+{
+    FactoryProvider factoryProvider;
+    switch(tag)
+    {
+        case (int) FactoryTags::kDacKey:
+            ChipLogProgress(SoftwareUpdate, "Set Device Attestation Key");
+            return factoryProvider.FactoryProvider::SetDeviceAttestationKey(newValue);
+        case (int) FactoryTags::kDacCert:
+            ChipLogProgress(SoftwareUpdate, "Set Device Attestation Cert");
+            return factoryProvider.FactoryProvider::SetDeviceAttestationCert(newValue);
+        case (int) FactoryTags::kPaiCert:
+            ChipLogProgress(SoftwareUpdate, "Set Product Attestionation Intermediate Cert");
+            return factoryProvider.FactoryProvider::SetProductAttestationIntermediateCert(newValue);
+        case (int) FactoryTags::kCdCert:
+            ChipLogProgress(SoftwareUpdate, "Set Certification Declaration");
+            return factoryProvider.FactoryProvider::SetCertificationDeclaration(newValue);
+ 
+    }
+
+
+    ChipLogError(DeviceLayer, "Failed to find tag %d.", tag);
+    return CHIP_ERROR_NOT_FOUND;
+}
+
+} // namespace chip
diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
new file mode 100644
index 00000000000000..e0b77d9fae062f
--- /dev/null
+++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
@@ -0,0 +1,82 @@
+/*
+ *
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <lib/core/Optional.h>
+#include <lib/support/ScopedBuffer.h>
+#include <lib/support/Span.h>
+#include <platform/silabs/multi-ota/OTATlvProcessor.h>
+#include <provision/ProvisionStorageGeneric.h> // nogncheck
+#include <provision/ProvisionStorage.h> // nogncheck
+
+namespace chip {
+
+/**
+ * OTA custom payload that uses Matter TLVs.
+ * The custom payload is used when factory data needs updating.
+ * Factory data will be encoded using Matter TLV format to make
+ * use of the ChipTlv reader. A payload contains metadata (size of
+ * TLVs) and the TLVs themselves contained in a structure.
+ * If no factory data need to be updated, the metadata will be 0
+ */
+struct OTAFactoryPayload
+{
+    Optional<ByteSpan> mCertDacKey;
+    Optional<ByteSpan> mCertDac;
+    Optional<ByteSpan> mCertPai;
+    Optional<ByteSpan> mCertDeclaration;
+
+    void Clear()
+    {
+        mCertDacKey.ClearValue();
+        mCertDac.ClearValue();
+        mCertPai.ClearValue();
+        mCertDeclaration.ClearValue();
+    }
+};
+
+enum class FactoryTags
+{
+    kDacKey = 1, 
+    kDacCert = 2 ,
+    kPaiCert = 3,
+    kCdCert = 4
+};
+
+class OTAFactoryDataProcessor : public OTATlvProcessor
+{
+public:
+    CHIP_ERROR Init() override;
+    CHIP_ERROR Clear() override;
+    CHIP_ERROR ApplyAction() override;
+    CHIP_ERROR FinalizeAction() override;
+
+
+private:
+    CHIP_ERROR ProcessInternal(ByteSpan & block) override;
+    CHIP_ERROR DecodeTlv();
+    CHIP_ERROR Update(uint8_t tag, Optional<ByteSpan> & optional);
+    CHIP_ERROR UpdateValue(uint8_t tag, ByteSpan & newValue);
+
+    OTAFactoryPayload mPayload;
+    OTADataAccumulator mAccumulator;
+    uint8_t * mFactoryData = nullptr;
+};
+
+} // namespace chip
diff --git a/src/platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.cpp b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp
similarity index 84%
rename from src/platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.cpp
rename to src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp
index fdf4c3d0321262..e20acfb252d970 100644
--- a/src/platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp
@@ -18,7 +18,7 @@
 
 #include <platform/internal/CHIPDeviceLayerInternal.h>
 #include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
-#include <platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.h>
+#include <platform/silabs/multi-ota/OTAFirmwareProcessor.h>
 
 #include <app/clusters/ota-requestor/OTARequestorInterface.h>
 
@@ -32,8 +32,6 @@ extern "C" {
 
 /// No error, operation OK
 #define SL_BOOTLOADER_OK 0L
-// TODO: more descriptive error codes
-#define SL_OTA_ERROR 1L
 
 namespace chip {
 
@@ -72,7 +70,33 @@ CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block)
     if (!mDescriptorProcessed)
     {
         ReturnErrorOnFailure(ProcessDescriptor(block));
+#if OTA_ENCRYPTION_ENABLE
+        /* 16 bytes to used to store undecrypted data because of unalignment */
+        mAccumulator.Init(requestedOtaMaxBlockSize + 16);
+#endif
+    }
+#if OTA_ENCRYPTION_ENABLE
+    MutableByteSpan mBlock = MutableByteSpan(mAccumulator.data(), mAccumulator.GetThreshold());
+    memcpy(&mBlock[0], &mBlock[requestedOtaMaxBlockSize], mUnalignmentNum);
+    memcpy(&mBlock[mUnalignmentNum], block.data(), block.size());
+
+    if (mUnalignmentNum + block.size() < requestedOtaMaxBlockSize)
+    {
+        uint32_t mAlignmentNum = (mUnalignmentNum + block.size()) / 16;
+        mAlignmentNum          = mAlignmentNum * 16;
+        mUnalignmentNum        = (mUnalignmentNum + block.size()) % 16;
+        memcpy(&mBlock[requestedOtaMaxBlockSize], &mBlock[mAlignmentNum], mUnalignmentNum);
+        mBlock.reduce_size(mAlignmentNum);
     }
+    else
+    {
+        mUnalignmentNum = mUnalignmentNum + block.size() - requestedOtaMaxBlockSize;
+        mBlock.reduce_size(requestedOtaMaxBlockSize);
+    }
+
+    OTATlvProcessor::vOtaProcessInternalEncryption(mBlock);
+    block = mBlock;
+#endif
 
     uint32_t blockReadOffset = 0;
     while (blockReadOffset < block.size())
@@ -88,7 +112,7 @@ CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block)
             if (err != SL_STATUS_OK)
             {
                 ChipLogError(SoftwareUpdate, "sl_wfx_host_pre_bootloader_spi_transfer() error: %ld", err);
-                return;
+                return CHIP_ERROR_CANCELLED;
             }
 #endif // SL_BTLCTRL_MUX
             CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);)
@@ -97,15 +121,12 @@ CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block)
             if (err != SL_STATUS_OK)
             {
                 ChipLogError(SoftwareUpdate, "sl_wfx_host_post_bootloader_spi_transfer() error: %ld", err);
-                return;
+                return CHIP_ERROR_CANCELLED;
             }
 #endif // SL_BTLCTRL_MUX
             if (err)
             {
                 ChipLogError(SoftwareUpdate, "bootloader_eraseWriteStorage() error: %ld", err);
-                // TODO: add this somewhere
-                // imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED);
-                // TODO: Replace CHIP_ERROR_CANCELLED with new error statement
                 return CHIP_ERROR_CANCELLED;
             }
             mWriteOffset += kAlignmentBytes;
diff --git a/src/platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.h b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.h
similarity index 100%
rename from src/platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.h
rename to src/platform/silabs/multi-ota/OTAFirmwareProcessor.h
diff --git a/src/platform/silabs/multi-ota/efr32/OTAHooks.cpp b/src/platform/silabs/multi-ota/OTAHooks.cpp
similarity index 53%
rename from src/platform/silabs/multi-ota/efr32/OTAHooks.cpp
rename to src/platform/silabs/multi-ota/OTAHooks.cpp
index cddb66980c27f9..cdf3d9de603345 100644
--- a/src/platform/silabs/multi-ota/efr32/OTAHooks.cpp
+++ b/src/platform/silabs/multi-ota/OTAHooks.cpp
@@ -21,7 +21,12 @@
 
 #include <app/clusters/ota-requestor/OTARequestorInterface.h>
 
-#include <platform/silabs/multi-ota/efr32/OTAFirmwareProcessor.h>
+#include <platform/silabs/multi-ota/OTAFirmwareProcessor.h>
+#include <platform/silabs/multi-ota/OTAFactoryDataProcessor.h>
+
+#if OTA_TEST_CUSTOM_TLVS
+#include <platform/silabs/multi-ota/OTACustomProcessor.h>
+#endif
 
 CHIP_ERROR chip::OTAMultiImageProcessorImpl::ProcessDescriptor(void * descriptor)
 {
@@ -34,11 +39,27 @@ CHIP_ERROR chip::OTAMultiImageProcessorImpl::ProcessDescriptor(void * descriptor
 CHIP_ERROR chip::OTAMultiImageProcessorImpl::OtaHookInit()
 {
     static chip::OTAFirmwareProcessor sApplicationProcessor;
+    static chip::OTAFactoryDataProcessor sFactoryDataProcessor;
 
     sApplicationProcessor.RegisterDescriptorCallback(ProcessDescriptor);
+    sFactoryDataProcessor.RegisterDescriptorCallback(ProcessDescriptor);
 
     auto & imageProcessor = chip::OTAMultiImageProcessorImpl::GetDefaultInstance();
-    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(1, &sApplicationProcessor));
+    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(static_cast<uint32_t>(OTAProcessorTag::kApplicationProcessor), &sApplicationProcessor));
+    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(static_cast<uint32_t>(OTAProcessorTag::kFactoryDataProcessor), &sFactoryDataProcessor));
+
+#if OTA_TEST_CUSTOM_TLVS
+    static chip::OTACustomProcessor customProcessor1;
+    static chip::OTACustomProcessor customProcessor2;
+    static chip::OTACustomProcessor customProcessor3;
+
+    customProcessor1.RegisterDescriptorCallback(ProcessDescriptor);
+    customProcessor2.RegisterDescriptorCallback(ProcessDescriptor);
+    customProcessor3.RegisterDescriptorCallback(ProcessDescriptor);
 
+    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(8, &customProcessor1));
+    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(9, &customProcessor2));
+    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(10, &customProcessor3));
+#endif
     return CHIP_NO_ERROR;
 }
diff --git a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp
index 147dcdaf8317ee..9dfb42fc879c4b 100644
--- a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp
+++ b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp
@@ -420,9 +420,6 @@ void OTAMultiImageProcessorImpl::HandleApply(intptr_t context)
 
     ChipLogProgress(SoftwareUpdate, "HandleApply: Finished");
 
-    // TODO: check where to put this
-    // ConfigurationManagerImpl().StoreSoftwareUpdateCompleted();
-
     // This reboots the device
     CORE_CRITICAL_SECTION(bootloader_rebootAndInstall();)
 }
diff --git a/src/platform/silabs/multi-ota/OTATlvProcessor.cpp b/src/platform/silabs/multi-ota/OTATlvProcessor.cpp
index a5da7eaba00c10..28da58db923f84 100644
--- a/src/platform/silabs/multi-ota/OTATlvProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTATlvProcessor.cpp
@@ -23,9 +23,12 @@
 #include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
 #include <platform/silabs/multi-ota/OTATlvProcessor.h>
 #if OTA_ENCRYPTION_ENABLE
-#include "OtaUtils.h"
-#include "rom_aes.h"
+#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
+#include <platform/silabs/SilabsConfig.h>
 #endif
+
+using namespace ::chip::DeviceLayer::Internal;
+
 namespace chip {
 
 #if OTA_ENCRYPTION_ENABLE
@@ -105,65 +108,10 @@ CHIP_ERROR OTADataAccumulator::Accumulate(ByteSpan & block)
 #if OTA_ENCRYPTION_ENABLE
 CHIP_ERROR OTATlvProcessor::vOtaProcessInternalEncryption(MutableByteSpan & block)
 {
-    uint8_t iv[16];
-    uint8_t key[kOTAEncryptionKeyLength];
-    uint8_t dataOut[16] = { 0 };
-    uint32_t u32IVCount;
-    uint32_t Offset = 0;
-    uint8_t data;
-    tsReg128 sKey;
-    aesContext_t Context;
-
-    memcpy(iv, au8Iv, sizeof(au8Iv));
-
-    u32IVCount = (((uint32_t) iv[12]) << 24) | (((uint32_t) iv[13]) << 16) | (((uint32_t) iv[14]) << 8) | (iv[15]);
-    u32IVCount += (mIVOffset >> 4);
-
-    iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
-    iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
-    iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
-    iv[15] = (uint8_t) (u32IVCount & 0xff);
-
-    if (Encoding::HexToBytes(OTA_ENCRYPTION_KEY, strlen(OTA_ENCRYPTION_KEY), key, kOTAEncryptionKeyLength) !=
-        kOTAEncryptionKeyLength)
-    {
-        // Failed to convert the OTAEncryptionKey string to octstr type value
-        return CHIP_ERROR_INVALID_STRING_LENGTH;
-    }
-
-    ByteSpan KEY = ByteSpan(key);
-    Encoding::LittleEndian::Reader reader_key(KEY.data(), KEY.size());
-    ReturnErrorOnFailure(reader_key.Read32(&sKey.u32register0)
-                             .Read32(&sKey.u32register1)
-                             .Read32(&sKey.u32register2)
-                             .Read32(&sKey.u32register3)
-                             .StatusCode());
-
-    while (Offset + 16 <= block.size())
-    {
-        /*Encrypt the IV*/
-        Context.mode         = AES_MODE_ECB_ENCRYPT;
-        Context.pSoftwareKey = (uint32_t *) &sKey;
-        AES_128_ProcessBlocks(&Context, (uint32_t *) &iv[0], (uint32_t *) &dataOut[0], 1);
-
-        /* Decrypt a block of the buffer */
-        for (uint8_t i = 0; i < 16; i++)
-        {
-            data = block[Offset + i] ^ dataOut[i];
-            memcpy(&block[Offset + i], &data, sizeof(uint8_t));
-        }
-
-        /* increment the IV for the next block  */
-        u32IVCount++;
-
-        iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
-        iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
-        iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
-        iv[15] = (uint8_t) (u32IVCount & 0xff);
-
-        Offset += 16; /* increment the buffer offset */
-        mIVOffset += 16;
-    }
+    uint32_t keyId;
+    SilabsConfig::ReadConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, keyId);
+    chip::DeviceLayer::Silabs::OtaTlvEncryptionKey::OtaTlvEncryptionKey key(keyId);
+    key.Decrypt(block, mIVOffset);
 
     return CHIP_NO_ERROR;
 }
diff --git a/src/platform/silabs/multi-ota/OTATlvProcessor.h b/src/platform/silabs/multi-ota/OTATlvProcessor.h
index 9e8e56a2b35825..0af153c1f0feab 100644
--- a/src/platform/silabs/multi-ota/OTATlvProcessor.h
+++ b/src/platform/silabs/multi-ota/OTATlvProcessor.h
@@ -43,6 +43,8 @@ namespace chip {
 #define CHIP_OTA_PROCESSOR_START_IMAGE CHIP_ERROR_TLV_PROCESSOR(0x0E)
 #define SL_GENERIC_OTA_ERROR CHIP_ERROR_TLV_PROCESSOR(0x0E)
 
+constexpr uint16_t requestedOtaMaxBlockSize = 1024;
+
 // Descriptor constants
 inline constexpr size_t kVersionStringSize = 64;
 inline constexpr size_t kBuildDateSize     = 64;
@@ -60,6 +62,14 @@ struct OTATlvHeader
     uint32_t length;
 };
 
+// TLV tags synced with ota files generate by scripts/tools/silabs/ota/ota_image_tool.py
+enum class OTAProcessorTag
+{
+    kApplicationProcessor = 1, 
+    kBootloaderProcessor = 2 ,
+    kFactoryDataProcessor = 3
+};
+
 /**
  * This class defines an interface for a Matter TLV processor.
  * Instances of derived classes can be registered as processors
diff --git a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
new file mode 100644
index 00000000000000..340db2412ecfe3
--- /dev/null
+++ b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
@@ -0,0 +1,132 @@
+#include "OtaTlvEncryptionKey.h"
+#include <lib/support/CodeUtils.h>
+#include <platform/silabs/SilabsConfig.h>
+#include <sl_psa_crypto.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Silabs {
+namespace OtaTlvEncryptionKey {
+
+using SilabsConfig = chip::DeviceLayer::Internal::SilabsConfig;
+
+int destroyAESKey(uint32_t kid)
+{
+    psa_key_handle_t key_handle;
+
+    int err = psa_open_key(kid, &key_handle);
+    if (err)
+    {
+        psa_close_key(kid);
+    }
+    else
+    {
+        err = psa_destroy_key(kid);
+    }
+    return err;
+}
+
+CHIP_ERROR OtaTlvEncryptionKey::Import(const uint8_t * key, size_t key_len)
+{
+    destroyAESKey(mId);
+
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_status_t status;
+
+    psa_key_id_t key_id;
+    psa_set_key_id(&attributes, mId);
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+    psa_set_key_bits(&attributes, 128);
+    psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
+    psa_set_key_usage_flags(
+        &attributes, PSA_KEY_USAGE_DECRYPT);
+    
+    status = psa_import_key(&attributes, key, key_len, &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("Failed to import a key error:%ld\n", status);
+        return CHIP_ERROR_INTERNAL;
+    }
+
+    return CHIP_NO_ERROR;
+
+}
+
+CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOffset)
+{
+    constexpr uint8_t au8Iv[] = { 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x00, 0x00, 0x00 };
+    uint8_t iv[16];
+    psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
+    psa_status_t status;
+    uint8_t output[PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES)];
+    size_t output_len;
+    size_t total_output;
+    uint32_t u32IVCount;
+    uint32_t Offset = 0;
+
+
+    memcpy(iv, au8Iv, sizeof(au8Iv));
+
+    u32IVCount = (((uint32_t) iv[12]) << 24) | (((uint32_t) iv[13]) << 16) | (((uint32_t) iv[14]) << 8) | (iv[15]);
+    u32IVCount += (mIVOffset >> 4);
+
+    iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
+    iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
+    iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
+    iv[15] = (uint8_t) (u32IVCount & 0xff);   
+
+    while (Offset + 16 <= block.size())
+    {
+        status = psa_cipher_decrypt_setup(&operation, static_cast<psa_key_id_t>(mId), PSA_ALG_CTR);
+        if (status != PSA_SUCCESS) {
+            printf("Failed to begin cipher operation error:%ld\n", status);
+            return CHIP_ERROR_INTERNAL;
+        }
+
+        status = psa_cipher_set_iv(&operation, iv, sizeof(iv));
+        if (status != PSA_SUCCESS) {
+            printf("Failed to set IV error:%ld\n", status);
+            return CHIP_ERROR_INTERNAL;
+        } 
+    
+        status = psa_cipher_update(&operation, static_cast<uint8_t *>(&block[Offset]), 16,
+                                   output, sizeof(output), &output_len);
+        if (status != PSA_SUCCESS) {
+            printf("Failed to update cipher operation error:%ld\n", status);
+            return CHIP_ERROR_INTERNAL;
+        }
+
+        /* increment the IV for the next block  */
+        u32IVCount++;
+
+        iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
+        iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
+        iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
+        iv[15] = (uint8_t) (u32IVCount & 0xff);
+
+        memcpy((void *) &block[Offset], &output, output_len);
+
+        Offset += 16; /* increment the buffer offset */
+        mIVOffset += 16;
+        status = psa_cipher_finish(&operation, output + total_output,
+                               sizeof(output) - total_output, &total_output);
+        if (status != PSA_SUCCESS) {
+        printf("Failed to finish cipher operation\n");
+        return CHIP_ERROR_INTERNAL;
+        }
+    
+    }
+    
+    printf("Decrypted ciphertext\n");
+
+    psa_cipher_abort(&operation);
+
+    return CHIP_NO_ERROR;
+}
+
+
+} // namespace Provision
+} // namespace Silabs
+} // namespace DeviceLayer
+} // namespace chip
\ No newline at end of file
diff --git a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
new file mode 100644
index 00000000000000..343132908170f6
--- /dev/null
+++ b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <lib/support/Span.h>
+#include <lib/core/CHIPError.h>
+#include <psa/crypto.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <platform/silabs/multi-ota/OTATlvProcessor.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Silabs {
+namespace OtaTlvEncryptionKey {
+
+static constexpr uint32_t kAES_KeyId_Default = (PSA_KEY_ID_USER_MIN + 2);
+
+class OtaTlvEncryptionKey
+{
+public:
+    OtaTlvEncryptionKey(uint32_t id = 0) { mId = (id > 0)? id : kAES_KeyId_Default; }
+    ~OtaTlvEncryptionKey() = default;
+
+    uint32_t GetId() { return mId; }
+    CHIP_ERROR Import(const uint8_t * key, size_t key_len);
+    CHIP_ERROR Decrypt(MutableByteSpan & block, uint32_t &mIVOffset);
+
+protected:
+    uint32_t mId = 0;
+    
+};
+
+} // namespace Provision
+} // namespace Silabs
+} // namespace DeviceLayer
+} // namespace chip
\ No newline at end of file
diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni
index 08695af1fc3800..ccbae7f1ec23ff 100644
--- a/third_party/silabs/efr32_sdk.gni
+++ b/third_party/silabs/efr32_sdk.gni
@@ -80,6 +80,8 @@ declare_args() {
 
   # Multi-chip OTA
   chip_enable_multi_ota_requestor = false
+  chip_enable_multi_ota_encryption = false
+  chip_enable_ota_custom_tlv_testing = false
 }
 
 examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32"
@@ -496,6 +498,14 @@ template("efr32_sdk") {
       ]
     }
 
+    if (chip_enable_multi_ota_encryption && chip_enable_multi_ota_requestor) {
+      defines += [ "OTA_ENCRYPTION_ENABLE=1" ]
+    }
+
+    if (chip_enable_ota_custom_tlv_testing && chip_enable_multi_ota_requestor) {
+      defines += [ "OTA_TEST_CUSTOM_TLVS=1" ]
+    }
+
     if (defined(invoker.chip_enable_wifi) && invoker.chip_enable_wifi) {
       if (enable_dic) {
         assert(chip_enable_wifi_ipv4, "enable chip_enable_wifi_ipv4")

From 5c1927f635885727c5032ee3c2f50b1c7ab82033 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Mon, 22 Jul 2024 14:54:47 +0000
Subject: [PATCH 02/10] Restyled by whitespace

---
 .../ota/examples/ota_custom_entries_example2.json  |  2 +-
 .../silabs/multi-ota/OTAFactoryDataProcessor.cpp   |  2 +-
 .../silabs/multi-ota/OTAFactoryDataProcessor.h     |  2 +-
 src/platform/silabs/multi-ota/OTATlvProcessor.h    |  2 +-
 .../silabs/multi-ota/OtaTlvEncryptionKey.cpp       | 14 +++++++-------
 .../silabs/multi-ota/OtaTlvEncryptionKey.h         |  4 ++--
 6 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json b/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json
index e850c91b909726..3b910f2d163156 100644
--- a/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json
+++ b/scripts/tools/silabs/ota/examples/ota_custom_entries_example2.json
@@ -85,4 +85,4 @@
             "path": "./binaries/ext_flash_ota_entry_example.bin"
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
index e89e9c027dc3b9..825eba260cdd3a 100644
--- a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
@@ -161,7 +161,7 @@ CHIP_ERROR OTAFactoryDataProcessor::UpdateValue(uint8_t tag, ByteSpan & newValue
         case (int) FactoryTags::kCdCert:
             ChipLogProgress(SoftwareUpdate, "Set Certification Declaration");
             return factoryProvider.FactoryProvider::SetCertificationDeclaration(newValue);
- 
+
     }
 
 
diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
index e0b77d9fae062f..9704e2c4080875 100644
--- a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
+++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
@@ -53,7 +53,7 @@ struct OTAFactoryPayload
 
 enum class FactoryTags
 {
-    kDacKey = 1, 
+    kDacKey = 1,
     kDacCert = 2 ,
     kPaiCert = 3,
     kCdCert = 4
diff --git a/src/platform/silabs/multi-ota/OTATlvProcessor.h b/src/platform/silabs/multi-ota/OTATlvProcessor.h
index 0af153c1f0feab..cf1c0458c6d049 100644
--- a/src/platform/silabs/multi-ota/OTATlvProcessor.h
+++ b/src/platform/silabs/multi-ota/OTATlvProcessor.h
@@ -65,7 +65,7 @@ struct OTATlvHeader
 // TLV tags synced with ota files generate by scripts/tools/silabs/ota/ota_image_tool.py
 enum class OTAProcessorTag
 {
-    kApplicationProcessor = 1, 
+    kApplicationProcessor = 1,
     kBootloaderProcessor = 2 ,
     kFactoryDataProcessor = 3
 };
diff --git a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
index 340db2412ecfe3..4a865832324cdf 100644
--- a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
+++ b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
@@ -42,7 +42,7 @@ CHIP_ERROR OtaTlvEncryptionKey::Import(const uint8_t * key, size_t key_len)
     psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
     psa_set_key_usage_flags(
         &attributes, PSA_KEY_USAGE_DECRYPT);
-    
+
     status = psa_import_key(&attributes, key, key_len, &key_id);
     if (status != PSA_SUCCESS) {
         printf("Failed to import a key error:%ld\n", status);
@@ -74,7 +74,7 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
     iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
     iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
     iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
-    iv[15] = (uint8_t) (u32IVCount & 0xff);   
+    iv[15] = (uint8_t) (u32IVCount & 0xff);
 
     while (Offset + 16 <= block.size())
     {
@@ -88,8 +88,8 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
         if (status != PSA_SUCCESS) {
             printf("Failed to set IV error:%ld\n", status);
             return CHIP_ERROR_INTERNAL;
-        } 
-    
+        }
+
         status = psa_cipher_update(&operation, static_cast<uint8_t *>(&block[Offset]), 16,
                                    output, sizeof(output), &output_len);
         if (status != PSA_SUCCESS) {
@@ -115,9 +115,9 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
         printf("Failed to finish cipher operation\n");
         return CHIP_ERROR_INTERNAL;
         }
-    
+
     }
-    
+
     printf("Decrypted ciphertext\n");
 
     psa_cipher_abort(&operation);
@@ -129,4 +129,4 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
 } // namespace Provision
 } // namespace Silabs
 } // namespace DeviceLayer
-} // namespace chip
\ No newline at end of file
+} // namespace chip
diff --git a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
index 343132908170f6..c2de313d0ff689 100644
--- a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
+++ b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
@@ -26,10 +26,10 @@ class OtaTlvEncryptionKey
 
 protected:
     uint32_t mId = 0;
-    
+
 };
 
 } // namespace Provision
 } // namespace Silabs
 } // namespace DeviceLayer
-} // namespace chip
\ No newline at end of file
+} // namespace chip

From d3354f6d5b947d685ef20ad8ab28096dbcc2afa3 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Mon, 22 Jul 2024 14:54:48 +0000
Subject: [PATCH 03/10] Restyled by clang-format

---
 .../provision/ProvisionStorageDefault.cpp     |  2 +-
 .../silabs/multi-ota/OTACustomProcessor.cpp   |  2 +-
 .../silabs/multi-ota/OTACustomProcessor.h     |  2 +-
 .../multi-ota/OTAFactoryDataProcessor.cpp     | 32 ++++++++---------
 .../multi-ota/OTAFactoryDataProcessor.h       |  9 +++--
 .../silabs/multi-ota/OTAFirmwareProcessor.cpp |  2 +-
 src/platform/silabs/multi-ota/OTAHooks.cpp    |  8 +++--
 .../silabs/multi-ota/OTATlvProcessor.cpp      |  2 +-
 .../silabs/multi-ota/OTATlvProcessor.h        |  2 +-
 .../silabs/multi-ota/OtaTlvEncryptionKey.cpp  | 36 +++++++++----------
 .../silabs/multi-ota/OtaTlvEncryptionKey.h    | 11 +++---
 11 files changed, 52 insertions(+), 56 deletions(-)

diff --git a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
index 410f43caaf341b..7e36f977498408 100644
--- a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
+++ b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
@@ -16,7 +16,6 @@
  */
 #include "AttestationKey.h"
 #include "ProvisionStorage.h"
-#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #include <credentials/examples/DeviceAttestationCredsExample.h>
 #include <lib/support/BytesToHex.h>
 #include <lib/support/CHIPMemString.h>
@@ -28,6 +27,7 @@
 #include <platform/CHIPDeviceConfig.h>
 #include <platform/silabs/MigrationManager.h>
 #include <platform/silabs/SilabsConfig.h>
+#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #include <silabs_creds.h>
 #ifdef SLI_SI91X_MCU_INTERFACE
 #include <sl_si91x_common_flash_intf.h>
diff --git a/src/platform/silabs/multi-ota/OTACustomProcessor.cpp b/src/platform/silabs/multi-ota/OTACustomProcessor.cpp
index 89c3cb133e3d46..85ceb7d44d4eaf 100644
--- a/src/platform/silabs/multi-ota/OTACustomProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTACustomProcessor.cpp
@@ -17,8 +17,8 @@
  */
 
 #include <platform/internal/CHIPDeviceLayerInternal.h>
-#include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
 #include <platform/silabs/multi-ota/OTACustomProcessor.h>
+#include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
 
 #include <app/clusters/ota-requestor/OTARequestorInterface.h>
 
diff --git a/src/platform/silabs/multi-ota/OTACustomProcessor.h b/src/platform/silabs/multi-ota/OTACustomProcessor.h
index 67980911d29be7..64610f4b41fa37 100644
--- a/src/platform/silabs/multi-ota/OTACustomProcessor.h
+++ b/src/platform/silabs/multi-ota/OTACustomProcessor.h
@@ -43,7 +43,7 @@ class OTACustomProcessor : public OTATlvProcessor
     CHIP_ERROR ProcessDescriptor(ByteSpan & block);
 
     OTADataAccumulator mAccumulator;
-    bool mDescriptorProcessed = false;
+    bool mDescriptorProcessed               = false;
     static constexpr size_t kAlignmentBytes = 64;
     static uint32_t mWriteOffset; // End of last written block
     static uint8_t mSlotId;       // Bootloader storage slot
diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
index 825eba260cdd3a..8d38207df35542 100644
--- a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp
@@ -22,7 +22,7 @@
 
 namespace chip {
 
-using FactoryProvider     = DeviceLayer::Silabs::Provision::Storage;
+using FactoryProvider = DeviceLayer::Silabs::Provision::Storage;
 
 CHIP_ERROR OTAFactoryDataProcessor::Init()
 {
@@ -69,7 +69,7 @@ CHIP_ERROR OTAFactoryDataProcessor::ProcessInternal(ByteSpan & block)
 
 CHIP_ERROR OTAFactoryDataProcessor::ApplyAction()
 {
-    CHIP_ERROR error           = CHIP_NO_ERROR;
+    CHIP_ERROR error = CHIP_NO_ERROR;
 
     SuccessOrExit(error = Update((uint8_t) FactoryTags::kDacKey, mPayload.mCertDacKey));
     SuccessOrExit(error = Update((uint8_t) FactoryTags::kDacCert, mPayload.mCertDac));
@@ -147,24 +147,22 @@ CHIP_ERROR OTAFactoryDataProcessor::Update(uint8_t tag, Optional<ByteSpan> & opt
 CHIP_ERROR OTAFactoryDataProcessor::UpdateValue(uint8_t tag, ByteSpan & newValue)
 {
     FactoryProvider factoryProvider;
-    switch(tag)
+    switch (tag)
     {
-        case (int) FactoryTags::kDacKey:
-            ChipLogProgress(SoftwareUpdate, "Set Device Attestation Key");
-            return factoryProvider.FactoryProvider::SetDeviceAttestationKey(newValue);
-        case (int) FactoryTags::kDacCert:
-            ChipLogProgress(SoftwareUpdate, "Set Device Attestation Cert");
-            return factoryProvider.FactoryProvider::SetDeviceAttestationCert(newValue);
-        case (int) FactoryTags::kPaiCert:
-            ChipLogProgress(SoftwareUpdate, "Set Product Attestionation Intermediate Cert");
-            return factoryProvider.FactoryProvider::SetProductAttestationIntermediateCert(newValue);
-        case (int) FactoryTags::kCdCert:
-            ChipLogProgress(SoftwareUpdate, "Set Certification Declaration");
-            return factoryProvider.FactoryProvider::SetCertificationDeclaration(newValue);
-
+    case (int) FactoryTags::kDacKey:
+        ChipLogProgress(SoftwareUpdate, "Set Device Attestation Key");
+        return factoryProvider.FactoryProvider::SetDeviceAttestationKey(newValue);
+    case (int) FactoryTags::kDacCert:
+        ChipLogProgress(SoftwareUpdate, "Set Device Attestation Cert");
+        return factoryProvider.FactoryProvider::SetDeviceAttestationCert(newValue);
+    case (int) FactoryTags::kPaiCert:
+        ChipLogProgress(SoftwareUpdate, "Set Product Attestionation Intermediate Cert");
+        return factoryProvider.FactoryProvider::SetProductAttestationIntermediateCert(newValue);
+    case (int) FactoryTags::kCdCert:
+        ChipLogProgress(SoftwareUpdate, "Set Certification Declaration");
+        return factoryProvider.FactoryProvider::SetCertificationDeclaration(newValue);
     }
 
-
     ChipLogError(DeviceLayer, "Failed to find tag %d.", tag);
     return CHIP_ERROR_NOT_FOUND;
 }
diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
index 9704e2c4080875..f7fd106de17220 100644
--- a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
+++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h
@@ -22,8 +22,8 @@
 #include <lib/support/ScopedBuffer.h>
 #include <lib/support/Span.h>
 #include <platform/silabs/multi-ota/OTATlvProcessor.h>
+#include <provision/ProvisionStorage.h>        // nogncheck
 #include <provision/ProvisionStorageGeneric.h> // nogncheck
-#include <provision/ProvisionStorage.h> // nogncheck
 
 namespace chip {
 
@@ -53,10 +53,10 @@ struct OTAFactoryPayload
 
 enum class FactoryTags
 {
-    kDacKey = 1,
-    kDacCert = 2 ,
+    kDacKey  = 1,
+    kDacCert = 2,
     kPaiCert = 3,
-    kCdCert = 4
+    kCdCert  = 4
 };
 
 class OTAFactoryDataProcessor : public OTATlvProcessor
@@ -67,7 +67,6 @@ class OTAFactoryDataProcessor : public OTATlvProcessor
     CHIP_ERROR ApplyAction() override;
     CHIP_ERROR FinalizeAction() override;
 
-
 private:
     CHIP_ERROR ProcessInternal(ByteSpan & block) override;
     CHIP_ERROR DecodeTlv();
diff --git a/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp
index e20acfb252d970..3fc66e53913b87 100644
--- a/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp
@@ -17,8 +17,8 @@
  */
 
 #include <platform/internal/CHIPDeviceLayerInternal.h>
-#include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
 #include <platform/silabs/multi-ota/OTAFirmwareProcessor.h>
+#include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
 
 #include <app/clusters/ota-requestor/OTARequestorInterface.h>
 
diff --git a/src/platform/silabs/multi-ota/OTAHooks.cpp b/src/platform/silabs/multi-ota/OTAHooks.cpp
index cdf3d9de603345..6be17441be473f 100644
--- a/src/platform/silabs/multi-ota/OTAHooks.cpp
+++ b/src/platform/silabs/multi-ota/OTAHooks.cpp
@@ -21,8 +21,8 @@
 
 #include <app/clusters/ota-requestor/OTARequestorInterface.h>
 
-#include <platform/silabs/multi-ota/OTAFirmwareProcessor.h>
 #include <platform/silabs/multi-ota/OTAFactoryDataProcessor.h>
+#include <platform/silabs/multi-ota/OTAFirmwareProcessor.h>
 
 #if OTA_TEST_CUSTOM_TLVS
 #include <platform/silabs/multi-ota/OTACustomProcessor.h>
@@ -45,8 +45,10 @@ CHIP_ERROR chip::OTAMultiImageProcessorImpl::OtaHookInit()
     sFactoryDataProcessor.RegisterDescriptorCallback(ProcessDescriptor);
 
     auto & imageProcessor = chip::OTAMultiImageProcessorImpl::GetDefaultInstance();
-    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(static_cast<uint32_t>(OTAProcessorTag::kApplicationProcessor), &sApplicationProcessor));
-    ReturnErrorOnFailure(imageProcessor.RegisterProcessor(static_cast<uint32_t>(OTAProcessorTag::kFactoryDataProcessor), &sFactoryDataProcessor));
+    ReturnErrorOnFailure(
+        imageProcessor.RegisterProcessor(static_cast<uint32_t>(OTAProcessorTag::kApplicationProcessor), &sApplicationProcessor));
+    ReturnErrorOnFailure(
+        imageProcessor.RegisterProcessor(static_cast<uint32_t>(OTAProcessorTag::kFactoryDataProcessor), &sFactoryDataProcessor));
 
 #if OTA_TEST_CUSTOM_TLVS
     static chip::OTACustomProcessor customProcessor1;
diff --git a/src/platform/silabs/multi-ota/OTATlvProcessor.cpp b/src/platform/silabs/multi-ota/OTATlvProcessor.cpp
index 28da58db923f84..91a748c077ec79 100644
--- a/src/platform/silabs/multi-ota/OTATlvProcessor.cpp
+++ b/src/platform/silabs/multi-ota/OTATlvProcessor.cpp
@@ -23,8 +23,8 @@
 #include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
 #include <platform/silabs/multi-ota/OTATlvProcessor.h>
 #if OTA_ENCRYPTION_ENABLE
-#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #include <platform/silabs/SilabsConfig.h>
+#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #endif
 
 using namespace ::chip::DeviceLayer::Internal;
diff --git a/src/platform/silabs/multi-ota/OTATlvProcessor.h b/src/platform/silabs/multi-ota/OTATlvProcessor.h
index cf1c0458c6d049..fe2070b75e5634 100644
--- a/src/platform/silabs/multi-ota/OTATlvProcessor.h
+++ b/src/platform/silabs/multi-ota/OTATlvProcessor.h
@@ -66,7 +66,7 @@ struct OTATlvHeader
 enum class OTAProcessorTag
 {
     kApplicationProcessor = 1,
-    kBootloaderProcessor = 2 ,
+    kBootloaderProcessor  = 2,
     kFactoryDataProcessor = 3
 };
 
diff --git a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
index 4a865832324cdf..10273e52f5a7a1 100644
--- a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
+++ b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.cpp
@@ -40,20 +40,19 @@ CHIP_ERROR OtaTlvEncryptionKey::Import(const uint8_t * key, size_t key_len)
     psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
     psa_set_key_bits(&attributes, 128);
     psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
-    psa_set_key_usage_flags(
-        &attributes, PSA_KEY_USAGE_DECRYPT);
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
 
     status = psa_import_key(&attributes, key, key_len, &key_id);
-    if (status != PSA_SUCCESS) {
+    if (status != PSA_SUCCESS)
+    {
         printf("Failed to import a key error:%ld\n", status);
         return CHIP_ERROR_INTERNAL;
     }
 
     return CHIP_NO_ERROR;
-
 }
 
-CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOffset)
+CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t & mIVOffset)
 {
     constexpr uint8_t au8Iv[] = { 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x00, 0x00, 0x00 };
     uint8_t iv[16];
@@ -65,7 +64,6 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
     uint32_t u32IVCount;
     uint32_t Offset = 0;
 
-
     memcpy(iv, au8Iv, sizeof(au8Iv));
 
     u32IVCount = (((uint32_t) iv[12]) << 24) | (((uint32_t) iv[13]) << 16) | (((uint32_t) iv[14]) << 8) | (iv[15]);
@@ -79,20 +77,22 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
     while (Offset + 16 <= block.size())
     {
         status = psa_cipher_decrypt_setup(&operation, static_cast<psa_key_id_t>(mId), PSA_ALG_CTR);
-        if (status != PSA_SUCCESS) {
+        if (status != PSA_SUCCESS)
+        {
             printf("Failed to begin cipher operation error:%ld\n", status);
             return CHIP_ERROR_INTERNAL;
         }
 
         status = psa_cipher_set_iv(&operation, iv, sizeof(iv));
-        if (status != PSA_SUCCESS) {
+        if (status != PSA_SUCCESS)
+        {
             printf("Failed to set IV error:%ld\n", status);
             return CHIP_ERROR_INTERNAL;
         }
 
-        status = psa_cipher_update(&operation, static_cast<uint8_t *>(&block[Offset]), 16,
-                                   output, sizeof(output), &output_len);
-        if (status != PSA_SUCCESS) {
+        status = psa_cipher_update(&operation, static_cast<uint8_t *>(&block[Offset]), 16, output, sizeof(output), &output_len);
+        if (status != PSA_SUCCESS)
+        {
             printf("Failed to update cipher operation error:%ld\n", status);
             return CHIP_ERROR_INTERNAL;
         }
@@ -109,13 +109,12 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
 
         Offset += 16; /* increment the buffer offset */
         mIVOffset += 16;
-        status = psa_cipher_finish(&operation, output + total_output,
-                               sizeof(output) - total_output, &total_output);
-        if (status != PSA_SUCCESS) {
-        printf("Failed to finish cipher operation\n");
-        return CHIP_ERROR_INTERNAL;
+        status = psa_cipher_finish(&operation, output + total_output, sizeof(output) - total_output, &total_output);
+        if (status != PSA_SUCCESS)
+        {
+            printf("Failed to finish cipher operation\n");
+            return CHIP_ERROR_INTERNAL;
         }
-
     }
 
     printf("Decrypted ciphertext\n");
@@ -125,8 +124,7 @@ CHIP_ERROR OtaTlvEncryptionKey::Decrypt(MutableByteSpan & block, uint32_t &mIVOf
     return CHIP_NO_ERROR;
 }
 
-
-} // namespace Provision
+} // namespace OtaTlvEncryptionKey
 } // namespace Silabs
 } // namespace DeviceLayer
 } // namespace chip
diff --git a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
index c2de313d0ff689..919e3b1285ac80 100644
--- a/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
+++ b/src/platform/silabs/multi-ota/OtaTlvEncryptionKey.h
@@ -1,11 +1,11 @@
 #pragma once
 
-#include <lib/support/Span.h>
 #include <lib/core/CHIPError.h>
+#include <lib/support/Span.h>
+#include <platform/silabs/multi-ota/OTATlvProcessor.h>
 #include <psa/crypto.h>
 #include <stddef.h>
 #include <stdint.h>
-#include <platform/silabs/multi-ota/OTATlvProcessor.h>
 
 namespace chip {
 namespace DeviceLayer {
@@ -17,19 +17,18 @@ static constexpr uint32_t kAES_KeyId_Default = (PSA_KEY_ID_USER_MIN + 2);
 class OtaTlvEncryptionKey
 {
 public:
-    OtaTlvEncryptionKey(uint32_t id = 0) { mId = (id > 0)? id : kAES_KeyId_Default; }
+    OtaTlvEncryptionKey(uint32_t id = 0) { mId = (id > 0) ? id : kAES_KeyId_Default; }
     ~OtaTlvEncryptionKey() = default;
 
     uint32_t GetId() { return mId; }
     CHIP_ERROR Import(const uint8_t * key, size_t key_len);
-    CHIP_ERROR Decrypt(MutableByteSpan & block, uint32_t &mIVOffset);
+    CHIP_ERROR Decrypt(MutableByteSpan & block, uint32_t & mIVOffset);
 
 protected:
     uint32_t mId = 0;
-
 };
 
-} // namespace Provision
+} // namespace OtaTlvEncryptionKey
 } // namespace Silabs
 } // namespace DeviceLayer
 } // namespace chip

From 9c888d2beaafeb5eddc793945d2f0ac875e93bd2 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Mon, 22 Jul 2024 14:54:48 +0000
Subject: [PATCH 04/10] Restyled by gn

---
 src/platform/silabs/efr32/BUILD.gn | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/platform/silabs/efr32/BUILD.gn b/src/platform/silabs/efr32/BUILD.gn
index ca65a25ff9944f..a71a0cd8b335e6 100644
--- a/src/platform/silabs/efr32/BUILD.gn
+++ b/src/platform/silabs/efr32/BUILD.gn
@@ -78,29 +78,29 @@ static_library("efr32") {
   }
 
   if (chip_enable_multi_ota_requestor) {
-    if(chip_enable_multi_ota_encryption) {
+    if (chip_enable_multi_ota_encryption) {
       sources += [
         "${silabs_platform_dir}/multi-ota/OtaTlvEncryptionKey.cpp",
         "${silabs_platform_dir}/multi-ota/OtaTlvEncryptionKey.h",
       ]
     }
 
-  if (chip_enable_ota_custom_tlv_testing) {
+    if (chip_enable_ota_custom_tlv_testing) {
       sources += [
         "${silabs_platform_dir}/multi-ota/OTACustomProcessor.cpp",
         "${silabs_platform_dir}/multi-ota/OTACustomProcessor.h",
       ]
     }
     sources += [
-      "${silabs_platform_dir}/multi-ota/OTAMultiImageProcessorImpl.cpp",
-      "${silabs_platform_dir}/multi-ota/OTAMultiImageProcessorImpl.h",
       "${silabs_platform_dir}/multi-ota/OTAFactoryDataProcessor.cpp",
       "${silabs_platform_dir}/multi-ota/OTAFactoryDataProcessor.h",
-      "${silabs_platform_dir}/multi-ota/OTATlvProcessor.cpp",
-      "${silabs_platform_dir}/multi-ota/OTATlvProcessor.h",
       "${silabs_platform_dir}/multi-ota/OTAFirmwareProcessor.cpp",
       "${silabs_platform_dir}/multi-ota/OTAFirmwareProcessor.h",
       "${silabs_platform_dir}/multi-ota/OTAHooks.cpp",
+      "${silabs_platform_dir}/multi-ota/OTAMultiImageProcessorImpl.cpp",
+      "${silabs_platform_dir}/multi-ota/OTAMultiImageProcessorImpl.h",
+      "${silabs_platform_dir}/multi-ota/OTATlvProcessor.cpp",
+      "${silabs_platform_dir}/multi-ota/OTATlvProcessor.h",
     ]
   } else if (chip_enable_ota_requestor) {
     sources += [

From 8730425be702d72a81b7d0e8f562fcac96806872 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Mon, 22 Jul 2024 14:54:52 +0000
Subject: [PATCH 05/10] Restyled by autopep8

---
 scripts/tools/silabs/factory_data_generator/custom.py | 1 +
 scripts/tools/silabs/ota/ota_multi_image_tool.py      | 1 +
 2 files changed, 2 insertions(+)

diff --git a/scripts/tools/silabs/factory_data_generator/custom.py b/scripts/tools/silabs/factory_data_generator/custom.py
index 00ee76178b51a0..888384b7b07add 100644
--- a/scripts/tools/silabs/factory_data_generator/custom.py
+++ b/scripts/tools/silabs/factory_data_generator/custom.py
@@ -51,6 +51,7 @@ def custom_function(self):
 from cryptography.hazmat.primitives.serialization import load_der_private_key
 from default import Base64Argument, FileArgument, IntArgument, StrArgument
 
+
 class DacPKey(FileArgument):
 
     def __init__(self, arg):
diff --git a/scripts/tools/silabs/ota/ota_multi_image_tool.py b/scripts/tools/silabs/ota/ota_multi_image_tool.py
index cd7ac6dbe2d253..280c80ea516a5d 100755
--- a/scripts/tools/silabs/ota/ota_multi_image_tool.py
+++ b/scripts/tools/silabs/ota/ota_multi_image_tool.py
@@ -63,6 +63,7 @@ class TAG:
     BOOTLOADER = 2
     FACTORY_DATA = 3
 
+
 def set_logger():
     stdout_handler = logging.StreamHandler(stream=sys.stdout)
     logging.basicConfig(

From b46007996217c111d0796bb95360316f7a943624 Mon Sep 17 00:00:00 2001
From: Michael Rupp <michael.rupp@silabs.com>
Date: Mon, 22 Jul 2024 11:10:55 -0400
Subject: [PATCH 06/10] remove unused libs caught by linter

---
 scripts/tools/silabs/factory_data_generator/custom.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/tools/silabs/factory_data_generator/custom.py b/scripts/tools/silabs/factory_data_generator/custom.py
index 888384b7b07add..a06d61ca3f8568 100644
--- a/scripts/tools/silabs/factory_data_generator/custom.py
+++ b/scripts/tools/silabs/factory_data_generator/custom.py
@@ -49,7 +49,7 @@ def custom_function(self):
 
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives.serialization import load_der_private_key
-from default import Base64Argument, FileArgument, IntArgument, StrArgument
+from default import FileArgument
 
 
 class DacPKey(FileArgument):

From 62920233557a44bc206cb7f5fdee592d46e6d380 Mon Sep 17 00:00:00 2001
From: Michael Rupp <michael.rupp@silabs.com>
Date: Mon, 22 Jul 2024 11:20:00 -0400
Subject: [PATCH 07/10] update doctree with new readmes

---
 docs/tools/index.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/docs/tools/index.md b/docs/tools/index.md
index 003573ed5ebb14..a2ff8fd1587f89 100644
--- a/docs/tools/index.md
+++ b/docs/tools/index.md
@@ -49,6 +49,8 @@ Source files for these tools are located at `scripts/tools`.
 :maxdepth: 1
 
 ../scripts/tools/silabs/README
+../scripts/tools/silabs/ota/README
+../scripts/tools/silabs/factory_data_generator/README
 
 ```
 

From 20d8bee3bea5d09882ef726e5a761f7e72cfd0c2 Mon Sep 17 00:00:00 2001
From: Michael Rupp <michael.rupp@silabs.com>
Date: Mon, 22 Jul 2024 11:29:53 -0400
Subject: [PATCH 08/10] rerun CI, cirque failing for unknown reasons


From de3283e6a7aaf08b75b180458f69bbd0e12b7851 Mon Sep 17 00:00:00 2001
From: Michael Rupp <michael.rupp@silabs.com>
Date: Mon, 22 Jul 2024 17:00:14 -0400
Subject: [PATCH 09/10] fix include guards in provision examples

---
 .../platform/silabs/provision/ProvisionStorageDefault.cpp   | 6 ++++--
 .../platform/silabs/provision/ProvisionStorageFlash.cpp     | 6 +++++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
index 7e36f977498408..1162323cda3d51 100644
--- a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
+++ b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp
@@ -27,8 +27,10 @@
 #include <platform/CHIPDeviceConfig.h>
 #include <platform/silabs/MigrationManager.h>
 #include <platform/silabs/SilabsConfig.h>
-#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #include <silabs_creds.h>
+#ifdef OTA_ENCRYPTION_ENABLE
+#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
+#endif // OTA_ENCRYPTION_ENABLE
 #ifdef SLI_SI91X_MCU_INTERFACE
 #include <sl_si91x_common_flash_intf.h>
 #else
@@ -660,7 +662,7 @@ CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value)
     ReturnErrorOnFailure(key.Import(value.data(), value.size()));
     return SilabsConfig::WriteConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, key.GetId());
 }
-#endif
+#endif // OTA_ENCRYPTION_ENABLE
 
 /**
  * @brief Reads the test event trigger key from NVM. If the key isn't present, returns default value if defined.
diff --git a/examples/platform/silabs/provision/ProvisionStorageFlash.cpp b/examples/platform/silabs/provision/ProvisionStorageFlash.cpp
index 5bd11108bd9cc6..f06d5c8309fdcd 100644
--- a/examples/platform/silabs/provision/ProvisionStorageFlash.cpp
+++ b/examples/platform/silabs/provision/ProvisionStorageFlash.cpp
@@ -25,6 +25,10 @@
 #include <platform/CHIPDeviceConfig.h>
 #include <platform/silabs/SilabsConfig.h>
 #include <string.h>
+#ifdef OTA_ENCRYPTION_ENABLE
+#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
+#endif // OTA_ENCRYPTION_ENABLE
+
 
 using namespace chip::Credentials;
 
@@ -708,7 +712,7 @@ CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value)
 {
     return CHIP_ERROR_NOT_IMPLEMENTED;
 }
-#endif
+#endif // OTA_ENCRYPTION_ENABLE
 
 CHIP_ERROR Storage::GetTestEventTriggerKey(MutableByteSpan & keySpan)
 {

From b6f3690ff7d79a0290b4af9ac76da68284e93a39 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Mon, 22 Jul 2024 21:01:10 +0000
Subject: [PATCH 10/10] Restyled by clang-format

---
 examples/platform/silabs/provision/ProvisionStorageFlash.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/examples/platform/silabs/provision/ProvisionStorageFlash.cpp b/examples/platform/silabs/provision/ProvisionStorageFlash.cpp
index f06d5c8309fdcd..35a32d6af8f5ec 100644
--- a/examples/platform/silabs/provision/ProvisionStorageFlash.cpp
+++ b/examples/platform/silabs/provision/ProvisionStorageFlash.cpp
@@ -29,7 +29,6 @@
 #include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
 #endif // OTA_ENCRYPTION_ENABLE
 
-
 using namespace chip::Credentials;
 
 #if SLI_SI91X_MCU_INTERFACE