.. include:: ../vars.rst .. _chapter-design-considerations: ********************* Design Considerations ********************* Enabling the |SP| will have an impact on your system. When you enable the |SP|, there are some processes that change (like Discovery) or that are new (like encrypting messages). Some of these processes involve cryptographic operations that are computationally expensive (increased CPU and memory usage); protecting data requires sending additional information on the wire (increased network traffic). This can affect both the performance and scalability of your system. Not every system is affected the same way. How much your system is affected will depend on the system architecture and requirements, as well as on its configuration. This chapter discusses some of the considerations that you should take into account when designing your system. .. contents:: :depth: 3 Factors Affecting Performance and Scalability in General ======================================================== There are some factors that have an impact on the performance and scalability of your system at all times. Security does have a cost. There are additional processes that impact CPU and memory usage, such as validating certificates and permissions, exchanging keys, encrypting samples, etc. Take into account that the memory representation of a |SecDP| and a |SecEP| is larger than for their unsecure counterparts. Hardware -------- Some processors have support for cryptographic hardware acceleration. Or your hardware may just have a fast enough processor for the additional overhead to not be a concern. .. note:: The OpenSSL libraries that we provide support hardware acceleration. Algorithms Used --------------- By default, the Cryptography Plugin uses AES-128 for symmetric encryption and decryption. This means that a 128-bit key will be used as an input for the AES algorithm. You can choose AES-192 or AES-256 encryption instead by configuring the :property:`cryptography.encryption_algorithm` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). Note that AES always performs the encryption and decryption operations in blocks of 128 bits. Using different encryption algorithms or key lengths will impact performance since CPU usage and the amount of data sent for key exchange may increase. Maximum Transmission Unit (MTU) ------------------------------- You can control the maximum size of the RTPS messages sent on the network by adjusting the :property:`message_size_max` property in your transport configuration (see :link_api_cpp98:`NDDS_Transport_Property_t::message_size_max in the RTI Connext DDS Traditional C++ API `). By setting this property to a value smaller than the maximum payload that fits in the MTU (usually 1472 bytes for UDP over Ethernet), you can avoid IP fragmentation. Hence, |CONNEXT| will fragment RTPS Submessages before sending them to the transport. Sending samples larger than the :property:`message_size_max` will result in DDS fragmentation, which requires Asynchronous Publishing if the |TOPIC| is reliable (see :link_um:`ASYNCHRONOUS_PUBLISHER QosPolicy (DDS Extension) in the Core Libraries User's Manual `). In scenarios with a hard limit on the transport maximum message size, the |SecKeyExchangeT| may require fragmentation, which requires enabling Asynchronous Publishing since it is a reliable |TOPIC| (see :numref:`p2_core/cryptography:Enabling Asynchronous Publishing for the Secure Key Exchange Topic`). However, if you want to use Origin Authentication Protection, RTPS messages and/or submessages will include a set of |RecSpecificMACs|. The maximum number of |RecSpecificMACs| that will be included in a message is determined by the :property:`cryptography.max_receiver_specific_macs` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). |RecSpecificMACs| cannot be fragmented into different submessages. Therefore, the absolute minimum :property:`message_size_max` you can use (even with Asynchronous Publishing) will depend on the :property:`cryptography.max_receiver_specific_macs` value. Note that each Receiver-specific MAC will be 20 bytes in size. Therefore, to avoid IP fragmentation, you have to limit the :property:`cryptography.max_receiver_specific_macs` property to a maximum of .. math:: \frac{\mathtt{message\_size\_max} - \mathtt{usable\_rtps\_size}}{20} where :math:`\mathtt{usable\_rtps\_size}` is the size of all packet bytes besides the MACs (including payload, RTPS headers and other security overhead). Generally, :math:`\mathtt{usable\_rtps\_size}` should be at least :math:`768 \mathrm{B}` to :math:`1 \mathrm{kB}`. Using OpenSSL Engines --------------------- The |SP| have support for OpenSSL engines (see :ref:`p3_advanced/openssl_engines:Support for OpenSSL Engines`). These engines are called by OpenSSL and provide alternative functions to the OpenSSL builtin cryptographic operations. Using different cryptographic functions may affect the performance of |SP|. For instance, the functions may perform optimized cryptographic operations, or use algorithms that have a reduced computational cost. On the other hand, your OpenSSL engine may implement more complex algorithms that require more CPU usage. OpenSSL engines may interact with hardware acceleration for common cryptographic operations, depending on the engine support. Security Plugins' Impact on Scalability at Startup ================================================== When a DDS system starts up, |DPs| discover each other through the |SDP| (see :link_um:`Discovery in the RTI Core Libraries User's Manual `). The scale of your system has a fundamental role in the time that it will take until it reaches a steady state where every |DP| knows all its peer |DPs| and user data flows through every part of the system where it is needed. Impact of the Security Plugins on the Discovery Process ------------------------------------------------------- When you enable the |SP|, your DDS applications will require some extra steps to create the |DPs| and perform the DDS Discovery process, as depicted in :numref:`figure-changes-discovery-process-SP-enabled`. These steps make sure that the security rules defined in your |GovernanceFile| apply, that |DPs| are mutually authenticated, and that they only have access to the data they are allowed to access (as defined in the |PermissionsFiles|), to cite a few examples. Let's assume that we are starting a DDS application that contains a local |DP| (|P1|) that will communicate with an existing remote |DP| (|P2|). Let's analyze the differences in Discovery (and application startup, in general) when we enable security. .. figure:: ../static/discovery-differences.png :scale: 50% :name: figure-changes-discovery-process-SP-enabled :align: center Changes in the Discovery Process When the |SP| Are Enabled Differences in DomainParticipant Creation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The first thing your application needs to communicate using DDS is a |DP|. The local |DP| (|P1|) is created from a certain configuration (default QoS or a selected profile). When you enable security, you need to specify additional settings to make your |DP| load the |SP| (see :ref:`p2_core/building_apps:Building and Running Security Plugins-Based Applications`). In addition, your |DP| will load the security artifacts that you specify in the properties. These artifacts include the |GovernanceFile|, |PermissionsFile|, Permissions CA, Identity CA, |IdentityCert| and |PrivateKey| (see :ref:`p1_welcome/using_dds_secure:Using Connext DDS Secure`). If any of these artifacts are missing, or if they cannot be verified/don't match (e.g., the |IdentityCert| is not signed by the provided Identity CA), the |DP| creation fails at this first stage. Your |DP| also needs permissions. We check whether it has a valid :xmltag:`grant` (matching the subject name in its |IdentityCert|) that is valid for the current date and time. If it doesn't, the creation of the |DP| fails immediately. Next, local participant-level permissions are checked to verify whether |P1| has permission to join the domain. If |P1| is not allowed to join the domain, the |DP| creation fails. For further details, refer to :ref:`p2_core/elements_dds_secure_system:How the Permissions are Interpreted`. Differences in Endpoints Creation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The local |DP| (|P1|) will have |DWs| and |DRs| for both builtin topics (such as the participant discovery |TOPIC|) and user-defined topics (user |EP| for data exchange). In addition, we need to allocate resources for discovering remote |DPs| and |EP|. When security is enabled, |PermissionsFiles| establish what |DPs| and |EP| are allowed to do. When you enable Endpoint-level permissions checking for a certain |TOPIC|, |P1| needs to verify whether it is allowed to publish/subscribe to that |TOPIC| before creating a |DW|/|DR| for it (see :ref:`p2_core/access_control:Topic-level rules`). If it is not allowed to do so, the endpoint creation fails. Differences in Remote DomainParticipants Discovery ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In the Participant Discovery phase, your local |DP| learns about other |DPs| in the domain, and vice-versa. As part of this process, the |DPs| exchange some details, including GUIDs, transport locators and DomainParticipantQos. These details only involve |DP| information (they do not involve |EP|). For further information, see :link_um:`Simple Participant Discovery in the Core Libraries User's Manual `. When security is enabled, the |DP| discovery is still exchanged unsecurely. In other words, the bootstrapping part of discovery happens without protection -- this only contains information about the |DP| that does not require protection and does not involve |EPs|. Participant declaration messages will include additional properties, as required by the DDS Security specification: * ``PID_PARTICIPANT_SECURITY_INFO`` validates Governance compatibility. If local and remote |GovernanceFiles| are not compatible, |P1| will reject matching |P2|. For further information, see :ref:`p2_core/elements_dds_secure_system:Elements of a Connext DDS Secure System`. * ``PID_IDENTITY_TOKEN`` contains summary information on the identity of a |DP|. The |SP| use the presence or absence of this token to determine whether or not the remote |DP| has security enabled. * ``PID_PERMISSIONS_TOKEN`` contains summary information on the permissions for a |DP|. The |SP| currently do not use this token. When |P1| and |P2| know about each other, they proceed to mutual authentication. As part of the Authentication process (1 in :numref:`figure-changes-discovery-process-SP-enabled`), |P1| and |P2| will exchange some artifacts by sending them on the wire as part of the handshake. These artifacts include the |IdentityCerts| and Permission Files. In the Authentication process, |P1| verifies |P2|'s |IdentityCert| against the Identity CA. If this verification fails, |P1| will reject communicating with |P2| (see :ref:`p2_core/authentication:Identity Certificate Validation`). This mutual authentication process happens in both directions. Next, |P1| checks that |P2| has the necessary permissions and that they are valid (2 in :numref:`figure-changes-discovery-process-SP-enabled`). If |P2| doesn't have a grant matching the subject name in its |IdentityCert|, |P1| will reject communicating with |P2|. If |P2|'s participant-level permissions are enabled (:xmltag:`enable_join_access_control` = :xmlval:`TRUE`), but |P2| does not have permission to join the domain, |P1| will also reject communicating with |P2| (see :ref:`p2_core/access_control:enable_join_access_control (within a domain_rule)`). Permissions checking also happens in both directions. As a result of the handshake, the two involved |DPs| will derive a Shared Key and establish a Secure Key Exchange Channel. The Cryptography plugin will use that channel to securely exchange the symmetric keys that the |EP| need to perform secure communication. After the handshake concludes with successful authentication and Shared Key derivation, symmetric cryptography is used to exchange other keys (see :ref:`p2_core/cryptography:Secure Key Exchange`). Differences in Remote Endpoints Discovery ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ During the Endpoint Discovery phase, your local |DP| learns about the |EP| of the remote |DPs|, and vice-versa. To do this, your |DP| sends publication/subscription declarations to inform discovered |DPs| about the local |DRs| and |DWs| and their properties (GUID, QoS, etc.). For details, see :link_um:`Simple Participant Discovery in the Core Libraries User's Manual `. These declarations are exchanged until each |DP| has a complete database of information about the |DPs| in its peers list and their entities. When a remote |DW|/|DR| is discovered, |CONNEXT| determines if the local application has a matching |DR|/|DW|. A 'match' between the local and remote entities occurs only if the |DR| and |DW| have the same |TOPIC|, same data type, and compatible QosPolicies. When security is enabled, |P1| and |P2| use the Secure Key Exchange Channel to exchange the Key Material for the Builtin Secure Endpoints (3 in :numref:`figure-changes-discovery-process-SP-enabled`), including the Publication Secure |DW| and |DR| used for secure endpoint discovery (see :ref:`p2_core/cryptography:Secure Key Exchange`). Note that secure endpoint discovery only applies to topics that enable it (see :ref:`p2_core/cryptography:enable_discovery_protection (topic_rule)`). At this point, |P1| performs endpoint discovery. For topics that enable |DiscoveryProtection|, endpoint declarations are sent over the |SecDiscoveryTopics|. Otherwise, the unsecure version of the Builtin Discovery Topics are used. In all cases, the |SP| check Governance compatibility by means of the ``PID_ENDPOINT_SECURITY_INFO`` parameter to check the endpoint security attributes and help perform matching decisions (see :ref:`p2_core/elements_dds_secure_system:Governance Compatibility Validation`). Then we will check the endpoint permissions, this time for the writers and the readers. Once your |DPs| go through all these steps, they will exchange keys for each of their |SecEntities| (see :ref:`p3_advanced/design_considerations:Impact of Key Exchange on Scalability at Startup`). After this, your |DPs| will enter the steady state where they will exchange user samples (see :ref:`p3_advanced/design_considerations:Security Plugins Impact on Scalability and Performance During Steady State`). Participant Discovery Information Validation and Updates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Initial Participant Discovery is a process that happens unprotected. However, Participant Discovery information is validated as part of the authentication process. This ensures that the right information is received during discovery, and that Participant Declaration Messages have not been injected by a malicious entity. In other words, Participant Discovery is mainly for bootstrapping, but then as part of authentication, we make sure that discovery information that we have received is valid. After authentication (and bootstrapping), any further updates that need to be propagated through participant discovery are sent over the secure version of the participant discovery |TOPIC|. Impact of the Secure Versions of Builtin Endpoints -------------------------------------------------- Secure versions of the Builtin Endpoints are always created when you enable the |SP|, regardless of the protection kind specified in the |GovernanceFile|. This generates additional traffic at startup in the form of :submsg:`HEARTBEATS` and :submsg:`ACKS` when a remote |DP| is discovered. Impact of Key Exchange on Scalability at Startup ------------------------------------------------ After Authentication (and key derivation) are complete, symmetric cryptography is used to exchange other keys. More concretely, two mutually authenticated |DPs| will use their exclusive secure key exchange channel (DCPSParticipantVolatileMessageSecure) to set the symmetric keys for both builtin and regular |EP|. When you enable security for a |TOPIC|, every |DW|/|DR| for that |TOPIC| will have its own |SenderKey| that needs to be sent to every matching |DR|/|DW|. These keys need to be generated and then exchanged between every pair of |DPs| publishing or subscribing to the secured |TOPIC|, which will have an impact on the network traffic and CPU usage. Note that this applies to both builtin and user-defined topics. For further details, refer to :ref:`p2_core/cryptography:Lifecycle of Secure Entities`. The following subsections describe the |SecEntities| whose Key Material must be exchanged by your |DPs|. Participant Key Material ^^^^^^^^^^^^^^^^^^^^^^^^ If you enable |RTPSProtection| by setting :xmltag:`rtps_protection_kind` to a value other than :xmlval:`NONE` in your |GovernanceFile|, your |DPs| will behave as |SecEntities| and they will have their own Key Material. |DPs| secured this way will need to exchange this Key Material in order to perform any secure communication. Builtin Secure Endpoints ^^^^^^^^^^^^^^^^^^^^^^^^ You can choose to use the secure version of the builtin |EP| to protect discovery and liveliness information for each of your topics. For example, you can use the |SecEPs| for discovery by setting :xmltag:`enable_discovery_protection` to :xmlval:`TRUE` in one of your topics. In this case, you will want to set the :xmltag:`discovery_protection_kind` to a value other than :xmlval:`NONE`; otherwise, you will not add any security. Note that enabling discovery protection for a |TOPIC| when the discovery protection kind is :xmlval:`NONE` is still a valid configuration that you can use for debuggability purposes. If :xmltag:`discovery_protection_kind` is other than :xmlval:`NONE`, your |DPs| will need to generate and exchange the Key Material for the secure version of the Builtin Discovery Endpoints, causing additional network usage. More concretely, the Cryptography Plugin will generate and exchange keys for the following |EP|: * DCPSParticipantSecure |DW| * DCPSParticipantSecure |DR| * DCPSPublicationSecure |DW| * DCPSPublicationSecure |DR| * DCPSSubscriptionSecure |DW| * DCPSSubscriptionSecure |DR| In addition, your |DPs| will need to apply the corresponding cryptographic transformation to discovery samples using |SubmsgProtection|. This comes with an additional computational cost and increased network usage (see :ref:`p3_advanced/design_considerations:Submessage Protection`). The same applies to |LivelinessProtection|. When you set :xmltag:`liveliness_protection_kind` to a value other than :xmlval:`NONE`, your |DPs| will exchange keys for the following |EPs|: * DCPSParticipantMessageSecure |DW| * DCPSParticipantMessageSecure |DR| Note that :xmltag:`discovery_protection_kind` also controls the level of protection that Builtin Secure Service Request Endpoints will have. Therefore, if :xmltag:`discovery_protection_kind` is a value other than :xmlval:`NONE`, keys for the following |EP| may need to be exchanged: * Service Request Secure |DW| * Service Request Secure |DR| .. note:: The creation of the Builtin Secure Discovery Endpoints is fully controlled by :xmltag:`discovery_protection_kind` and does not depend on the value of :xmltag:`enable_discovery_protection` on particular topics. Similarly, the Builtin Secure Liveliness Endpoints' creation only depends on :xmltag:`liveliness_protection_kind`, not on the value of :xmltag:`enable_liveliness_protection` on particular topics. Finally, the Builtin Secure Logging Endpoints will apply :xmlval:`SIGN` [#f1]_ protection to RTPS Submessages for logged security events. Note that the Builtin Secure Logging Endpoints will only be created when you set the :value:`SECURITY_TOPIC` mask in the :property:`logging.mode_mask` property [#f2]_ (see :numref:`RTI Security Plugins Properties for Configuring Logging`). In this case, keys for the Builtin Logging |DW| and matching |DRs| will need to be exchanged. For further details on the Builtin Secure Endpoints, refer to :ref:`p2_core/elements_dds_secure_system:Security Builtin Topics`. .. [#f1] In |CONNEXT| 5.3.0, the |LoggingT| did not use |SubmsgProtection| (which did not comply with the DDS Security specification). For backward compatibility with 5.3.0, you can choose to disable |SubmsgProtection| in this |TOPIC| with the :property:`access_control.use_530_logging_protection` property (see :numref:`Additional RTI Security Plugins Properties for Configuring Logging Distributed Over DDS`). .. [#f2] In |CONNEXT| 6.0.1 and before, the creation of the Builtin Secure Logging Endpoints was controlled with the :property:`logging.distribute.enable` property. User-Defined Secure Endpoints ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can choose to protect each of the user-defined topics separately. The impact of exchanging keys for your user-defined secure endpoints will be directly related to the number of Endpoints in your participants. By default, |SubmsgProtection| and |DataProtection| use the same Key Material. Therefore, each of your topics will have a single key, regardless of whether you protect your |TOPIC| with |SubmsgProtection|, |DataProtection|, or both. You can choose not to use the same keys for Serialized Data and Submessage Protections by setting the :property:`cryptography.share_key_for_metadata_and_data_protection` property to :value:`FALSE`, as specified in :numref:`RTI Security Plugins Properties for Configuring Cryptography`. Then your participants will need to generate and exchange two different keys for each of your |SecDWs|. .. list-table:: Size of the RTPS message containing the Key Material exchanged on the wire for each |Entity|, assuming AES-GCM-128, which has a key length of 16 Bytes :name: Size of the RTPS message containing the Key Material :widths: auto :header-rows: 1 :class: longtable * - Without Origin Authentication Protection - With Origin Authentication Protection (requries sending an additional receiver-specific key) * - 364 Bytes - 380 Bytes You can estimate the number of keys your |DPs| will put on the network for your user-defined endpoints. For each |TOPIC|, multiply the number of |DWs| by the number of compatible |DRs| (i.e., matching |DRs| with compatible QoS). The sum will tell you how many keys will be exchanged. Note that |SP| does not support Key Material renewal. As a consequence, this key exchange only happens once when new endpoints are discovered. In addition, when you use Topic Queries (see :link_um:`Topic Queries in the Core Libraries User's Manual `), one additional key is exchanged per matching |DW|/|DR|. This is required because internally, |CONNEXT| uses two GUIDs for each |DW|. The same mechanism is put in place for Multi-channel |DWs| (see :link_um:`Multi-channel DataWriters in the Core Libraries User's Manual `). In this latter case, :math:`N-1` additional keys are exchanged, where :math:`N` is the number of channels. Receiver-Specific Keys ^^^^^^^^^^^^^^^^^^^^^^ If you enable the Origin Authentication Protection for a |TOPIC|, each |SecEntity| for that |TOPIC| will have its own receiver-specific key. This implies that the Key Material for |DWs| and |DRs| of that |TOPIC| will be around :math:`1.5\times` the size since it will include a |SenderKey| and a Receiver-specific Key. This implies that topics protected with Origin Authentication Protection will produce around :math:`1.5\times` the traffic during the key exchange process. Note that you can apply Origin Authentication Protection to either builtin and user-defined topics by tuning the corresponding |GovRules| (see :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities`). Factors Impacting Performance and Scalability at Startup -------------------------------------------------------- Now you know the additional processes that happen when security is enabled. Now we will list a set of factors that will impact scalability at startup. Number of Participants and Endpoints in Your Secure Domain ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The number of participants in your |SecDomain| will certainly have an impact on scalability. The reason is that discovery and mutual authentication occur between each pair of |DPs|. This is not much different from the unsecure scenario. However, the |SP| add Discovery time, both by adding additional operations and sending additional messages and files. In general, you can expect :math:`3\times` the traffic you would have without security for each pair of |DPs|. Also, since every |DP| needs to authenticate with every other |DP| in your |SecDomain|, the traffic will increase as the number of participants grows. If the discovery traffic for each pair of |DPs| increases by :math:`3`, then the traffic in your |SecDomain| will increase by :math:`1.5\cdot N\cdot (N-1)`, where :math:`N` is the number of participants in your |SecDomain|. The factors that you can tune and that will have the bigger impact are covered below. Contents of the Identity Certificates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ During the Authentication process, |DPs| exchange their Identity Certificates (as specified in the :property:`dds.sec.auth.identity_certificate` property in :numref:`DDS Security Properties for Configuring Authentication`. These artifacts are X.509 digital certificates in PEM format that may include a human-readable part and the Base64 representation of the certificate. By default, the |SP| trim out the human-readable part of the certificate before sending it to save some bandwidth. You may want to have the human-readable part sent for debugging purposes. You can control this behavior with the :property:`authentication.propagate_simplified_identity_certificate` property. Contents of Your Permissions Files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ During the Authentication process, |DPs| exchange their |PermissionsDoc| (as specified in the :property:`dds.sec.access.permissions` property in :numref:`DDS Security Properties for Configuring Authentication`. The Permissions Document is specified in an XML file that defines the access control permissions per domain and per |TOPIC| for individual |DPs|. The Permissions CA must sign the |PermissionsFile|. Hence, the |PermissionsFile| is sent "as is" on the wire so that other |DPs| can verify the signature. You can potentially set the same |PermissionsFile| across all of the participants in your system. For example, you have |P1| load a |PermissionsFile| that includes permissions for both |P1| and |P2|. Then, you can have |P2| load the same |PermissionsFile|. Having the same |PermissionsFile| across all the participants in your system can be handy for prototyping. However, it requires sending the same |PermissionsFile| on the network during each authentication. A better option would be to define the permissions so that you use a different file for each of your participants. For |P1| you will have the permissions for that participant, for |P2|, you will have the permissions for that different participant. This way, you will reduce network traffic by not sending unnecessary information, especially if you have a big system with hundreds of participants. Selecting the right granularity for your |PermissionsFiles| has a big impact on scalability. For example, compare the following scenarios in a system with :math:`100` participants. #. Each participant has its own |PermissionsFile| containing only one grant: each participant sends its permissions to every other participant (:math:`100\times 1\times 99 = 9,900` permission grants exchanged). #. All the participants have the same |PermissionsFile|: each participant sends around :math:`N` times its permissions to every other participant (:math:`100\times 100\times 99 = 990,000` permission grants exchanged) Assuming that the permission grant for a single participant is around :math:`1 \mathrm{kB}` in size, with only :math:`100` participants you can reduce the total network load from :math:`990 \mathrm{MB}` to around :math:`10 \mathrm{MB}`, saving up to :math:`980 \mathrm{MB}` of network traffic. As a general rule, :math:`N\times (N-1)` |PermissionsDoc| are sent on your network (where :math:`N` is the number of |DPs| in your |SecDomain|). Impact of Different Protection Kinds ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you use |DiscoveryProtection|, some parts of the discovery process will require additional cryptographic operations (see :ref:`p2_core/cryptography:discovery_protection_kind (domain_rule)`). In this case, part of the messages sent during discovery will be protected with |SubmsgProtection| (see :ref:`p2_core/cryptography:Submessage Protection`), at the level specified by the :xmltag:`discovery_protection_kind` |GovRule|. Also, when you set different protection kinds, symmetric keys need to be exchanged, which will be sent on the network through the Secure Key Exchange Channel. For instance, additional Receiver-specific keys are exchanged when you use Origin Authentication Protection. See :ref:`p3_advanced/design_considerations:Impact of Key Exchange on Scalability at Startup`, where we explain which protection kinds require sending which keys. Here is a summary of the keys that need to be generated and exchanged: - :xmlval:`ENCRYPT` and :xmlval:`SIGN` protections will require exchanging one key per |DW| and |DR| of the |TOPIC| being protected. By default, this is independent of where you apply the protection (see :ref:`p3_advanced/design_considerations:User-defined Secure Endpoints`). - Protection kinds ending in :xmlval:`_WITH_ORIGIN_AUTHENTICATION` will require exchanging one additional key per |DW| and |DR| of the |TOPIC| being protected. Security Plugins Impact on Scalability and Performance During Steady State ========================================================================== The |SP|' impact on performance will depend on multiple factors, including the security requirements of your systems, hardware considerations, and interactions with other |CONNEXT| features. Overhead of the Different Protection Kinds ------------------------------------------ When an application uses security, the contents of the RTPS packets will be different. For example, cryptographic metadata will be added around the protected parts, which may be encrypted depending on the configured protection. Protecting your data will always have an overhead. Depending on what you protect (user data, metadata, rtps packet, liveliness, etc), different parts of the RTPS packets will be different. The following sections discuss the packet growth that you can expect for each of the protection kinds. Discovery Protection ^^^^^^^^^^^^^^^^^^^^ You can enable |DiscoveryProtection| by setting the :xmltag:`discovery_protection_kind` |GovRule| to a value other than :xmlval:`NONE`. The greatest impact of enabling |DiscoveryProtection| for a |TOPIC| is at startup, since the discovery data for that |TOPIC| will be sent protected (increased CPU and network usage, as explained in :ref:`p3_advanced/design_considerations:Builtin Secure Endpoints`). Still, it has some impact on steady state, since TopicQuery requests related to your |TOPIC| will be exchanged through the |SecServiceReqTopic|, whose configuration is controlled the same way as |SecDiscoveryEPs| (see :ref:`p2_core/cryptography:Builtin Secure Discovery Endpoints` and :ref:`p3_advanced/design_considerations:Interaction with Topic Queries`). You could also modify some of your |DW|/|DR| QoS policies (such as partitions), or a network change could indirectly trigger a change in the |DW|/|DR| information. In this situation, the policies need to be propagated. If |DiscoveryProtection| is enabled for your |TOPIC|, the endpoint declarations used to propagate the QoS will be sent using the |SecDiscoveryEPs| (see :ref:`p2_core/cryptography:Builtin Secure Discovery Endpoints`). These endpoints will apply RTPS |SubmsgProtection| to the level you configure with the :xmltag:`discovery_protection_kind` |GovRule|, increasing both CPU usage and network usage. (For the overhead caused by the |SubmsgProtection|, see :ref:`p3_advanced/design_considerations:Submessage Protection`.) Finally, you could modify some of your DomainParticipantQos policies. If |DiscoveryProtection| is enabled, the participant declarations used to propagate the QoS will be sent using the |SecDiscoveryEPs| (see :ref:`p2_core/cryptography:Builtin Secure Discovery Endpoints`). Note that participant declarations are also sent on IP mobility events (and these will be protected if |DiscoveryProtection| is enabled). For further information, see :ref:`p2_core/cryptography:RTPS Protocol Changes to Support Secure Entities Traffic`. Liveliness Protection ^^^^^^^^^^^^^^^^^^^^^ You can enable |LivelinessProtection| by setting the :xmltag:`liveliness_protection_kind` |GovRule| to a value other than :xmlval:`NONE`. When you enable |LivelinessProtection| for a |TOPIC|, liveliness information related to your |TOPIC| will be exchanged through the Builtin Secure Liveliness Endpoints (only if the LIVELINESS QosPolicy is set to :value:`AUTOMATIC` or :value:`MANUAL_BY_PARTICIPANT`). These endpoints will apply RTPS |SubmsgProtection| to the level you configure with the :xmltag:`liveliness_protection_kind` |GovRule|, increasing both CPU usage and network usage. (For the overhead caused by the |SubmsgProtection|, see :ref:`p3_advanced/design_considerations:Submessage Protection`.) For further information, see :ref:`p2_core/cryptography:RTPS Protocol Changes to Support Secure Entities Traffic`. Serialized Data Protection ^^^^^^^^^^^^^^^^^^^^^^^^^^ You can enable |DataProtection| by setting the :xmltag:`data_protection_kind` |GovRule| to a value other than :xmlval:`NONE`. When you enable |DataProtection|, data in the |DW|'s queue will be protected before encapsulating it in an RTPS Submessage. Therefore, user data is only protected once and retransmissions do not need re-encryption. The length of the data field increases (in the RTPS Submessage) because the ``serializedData`` field now includes a header and a footer with cryptographic information. The |CryptoHeader| includes information such as an identifier for the key used to encrypt the payload. The |CryptoFooter| includes the generated message authentication code (MAC). This extra information allows the receiver to decrypt the message (when needed) and verify its integrity. See :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities` and :ref:`p2_core/cryptography:RTPS Protocol Changes to Support Secure Entities Traffic`. More concretely, each sample (i.e., :submsg:`DATA` submessage) sent by your |DWs| will have an additional 40 bytes (in the case of :xmlval:`SIGN` protection) or 44 bytes (in the case of :xmlval:`ENCRYPT` protection), as shown in :numref:`Expected growth of serialized payload when applying Serialized Data Protection`. **This is independent of the sample length.** Note that, in some cases, this overhead could trigger fragmentation for samples that were just below the fragmentation limit before applying the protection. .. list-table:: Expected Growth of serialized payload when applying Serialized Data Protection, in Bytes :name: Expected growth of serialized payload when applying Serialized Data Protection :widths: auto :header-rows: 1 :class: longtable * - Element - Extra bytes when using :xmlval:`SIGN` - Extra bytes when using :xmlval:`ENCRYPT` * - |CryptoHeader| - 20 - 20 * - |CryptoContent| - 0 - 4 * - |CryptoFooter| - 20 - 20 * - Total - 40 - 44 Submessage Protection ^^^^^^^^^^^^^^^^^^^^^ You can enable |SubmsgProtection| by setting the :xmltag:`metadata_protection_kind` |GovRule| to a value other than :xmlval:`NONE`. |SubmsgProtection| applies to messages sent both by the |DW| and the |DR|. Secure Endpoints will protect submessages right before putting them on the network. Note that a batch containing multiple samples is considered a single submessage. Refer to :ref:`p2_core/cryptography:Submessage Protection` for a comprehensive list of all protected submessages. Note that |SubmsgProtection| implies adding a Secure Prefix Submessage and a Secure Postfix Submessage to the RTPS message. For further details, see :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities` and :ref:`p2_core/cryptography:RTPS Protocol Changes to Support Secure Entities Traffic`. The growth in size caused by |SubmsgProtection| is slightly higher than with |DataProtection|. However, note that |SubmsgProtection| applies to submessages sent by both |DWs| and |DRs| for the |TOPIC| being protected. Therefore, each submessage protected by your |DWs| or |DRs| will have an additional 48 bytes (in the case of :xmlval:`SIGN`) or 56 bytes (in the case of :xmlval:`ENCRYPT`), as shown in :numref:`Expected growth of serialized payload when applying Submessage Protection`. This overhead is independent of the sample length. If you enable Origin Authentication Protection (with :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or with :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`), each submessage that your |DWs| and |DRs| protect will have an additional 20 bytes in the |CryptoFooter| per matching |DR|/|DW|. This overhead is limited by the :property:`cryptography.max_receiver_specific_macs` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). .. list-table:: Expected Growth of Serialized Payload When Applying |SubmsgProtection|, in Bytes :name: Expected growth of serialized payload when applying Submessage Protection :widths: auto :header-rows: 1 :class: longtable * - Element - Extra bytes when using :xmlval:`SIGN` - Extra bytes when using :xmlval:`ENCRYPT` - Extra bytes when using :xmlval:`_WITH_ORIGIN_AUTHENTICATION` [#f3]_ * - :submsg:`SEC_PREFIX` - 24 - 24 - 0 * - :submsg:`SEC_BODY` - 0 - 8 - 0 * - :submsg:`SEC_POSTFIX` - 24 - 24 - 20 per matching entity * - Total - 48 - 56 - 20 per matching entity .. [#f3] This overhead is limited by the :property:`cryptography.max_receiver_specific_macs` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). RTPS Protection ^^^^^^^^^^^^^^^ You can enable |RTPSProtection| by setting the :xmltag:`rtps_protection_kind` |GovRule| to a value other than :xmlval:`NONE`. |RTPSProtection| affects the |DP| and applies to every packet that is sent by protecting the whole RTPS message right before putting it on the network. The only exception to |RTPSProtection| is: * Traffic during the initial Participant Discovery used in the bootstrapping, which is never protected. * Traffic of the |AuthT| (|AuthTName|), which is never protected. * Traffic of the |SecKeyExchangeT| (|SecKeyExchangeTName|), which use :xmlval:`ENCRYPT` protection at the Submessage level instead. For further details, see :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities` and :ref:`p2_core/cryptography:RTPS Protocol Changes to Support Secure Entities Traffic`. |RTPSProtection| implies a growth in every RTPS message that your |DPs| send on the |SecDomain| [#]_. Each RTPS message sent by your participants will have an additional 72 bytes (in the case of :xmlval:`SIGN`) or 80 bytes (in the case of :xmlval:`ENCRYPT`), as shown in :numref:`Expected growth of serialized size when applying RTPS Protection`. This is independent of the sample length. If you enable Origin Authentication Protection (with :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or with :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`), each RTPS message sent by your participant will have an additional 20 bytes in the |CryptoFooter| per receiver. This overhead is limited by the :property:`cryptography.max_receiver_specific_macs` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). The number of |RecSpecificMACs| in an RTPS message is the union of the |RecSpecificMACs| each of its submessages would need. For example, assume that you have an RTPS message with three submessages. The first submessage is directed to a receiver A, the receiver of the second submessage is B, and the receiver of the third submessage is unknown. In this situation, if |SubmsgProtection| was set to protect the Origin Authentication, the first submessage would have the receiver-specific MAC for A, the second submessage would have the receiver-specific MAC for B, and the third submessage would have the receiver-specific MAC for all the matching Endpoints, let's say A, B, C, and D. Therefore, to satisfy the requirements of every submessage, the RTPS message will include the following |RecSpecificMACs|: .. math:: \lbrace A\rbrace\cup\lbrace B\rbrace\cup\lbrace A,B,C,D\rbrace=\lbrace A,B,C,D\rbrace .. figure:: ../static/rec-specific-macs-multiple-receivers.png :scale: 50% :name: design_considerations:Receiver-specific MACs included in an RTPS Message that uses RTPS Protection with Origin Authentication :align: center Receiver-Specific MACs Included in an RTPS Message that Uses RTPS Protection with Origin Authentication .. list-table:: Expected Growth of Serialized Size When Applying |RTPSProtection|, in Bytes :name: Expected growth of serialized size when applying RTPS Protection :widths: auto :header-rows: 1 :class: longtable * - Element - Extra bytes when using :xmlval:`SIGN` - Extra bytes when using :xmlval:`ENCRYPT` - Extra bytes when using :xmlval:`_WITH_ORIGIN_AUTHENTICATION` [#f4]_ * - :submsg:`SRTPS_PREFIX` - 24 - 24 - 0 * - :submsg:`SRTPS_BODY` - 24 - 32 - 0 * - :submsg:`SRTPS_POSTFIX` - 24 - 24 - 20 per matching entity * - Total - 72 - 80 - 20 per matching entity .. [#f4] This overhead is limited by the :property:`cryptography.max_receiver_specific_macs` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). .. [#] Exceptions of RTPS messages to which |RTPSProtection| applies are covered in :ref:`p2_core/cryptography:DomainParticipants`. Origin Authentication Protection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Origin Authentication protection allows the Receiver to make sure that the Sender is who it claims to be (i.e., it can authenticate the origin), even when the Sender is communicating with multiple Receivers via multicast and shares the same encryption key with all of them. You can add Origin Authentication protection to |SubmsgProtection| by setting the :xmltag:`metadata_protection_kind` |GovRule| to :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`. You can add Origin Authentication protection to |RTPSProtection| by setting the :xmltag:`rtps_protection_kind` |GovRule| to :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`. This protection involves computing additional |RecSpecificMACs| with a secret key that the Sender shares only with one Receiver. More concretely, the |CryptoFooter| will contain 1 additional MAC for every receiver targeted by the message. For example, if a |DW| sends a message to 10 different |DRs| (in 10 different |DPs|), you can expect 10 additional MACs added to the |CryptoFooter|. Note that Receivers in the same remote |DP| will share the Receiver-specific Key and therefore, a single |RecSpecificMAC| will be added for all of them. You can limit the number of |RecSpecificMACs| that are appended to a message by tuning the :property:`cryptography.max_receiver_specific_macs` property. For further information, see :ref:`p2_core/cryptography:Origin Authentication Protection Implications`. Note that the major implication of this protection is that |RecSpecificMACs| will be added to the packet, which increases its length. SIGN VS ENCRYPT ^^^^^^^^^^^^^^^ :xmlval:`ENCRYPT` protection is slightly more expensive than :xmlval:`SIGN`. Since :xmlval:`ENCRYPT` adds a length field in the |CryptoContent|, the network usage of :xmlval:`ENCRYPT` is slightly greater than the network usage of :xmlval:`SIGN`. The computational cost of :xmlval:`ENCRYPT` is also higher than :xmlval:`SIGN`, especially as the sample gets larger. However, the difference between :xmlval:`SIGN` and :xmlval:`ENCRYPT` protections is so small that the impact on throughput and latency is usually minimal. Please note that you can combine :xmlval:`SIGN` and :xmlval:`ENCRYPT` by applying different protections at different stages. For example, you can potentially protect the integrity and confidentiality of a particular |TOPIC|'s payload (by setting |DataProtection| to :xmlval:`ENCRYPT` for that |TOPIC|) while protecting the integrity of all the traffic (by setting |RTPSProtection| to :xmlval:`SIGN`). In this scenario, your application will require :math:`\sim 2 \times` CPU time to compute the cryptographic operations, if we compare it with a scenario where a single protection is enabled. Enabling different protections at the same time will certainly impact the throughput and latency of your application. For further information on what entities are responsible for each protection kind, see :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities`. Factors Impacting Performance and Scalability During Steady State ----------------------------------------------------------------- Performance Impact of Different Protection Kinds ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The protection kinds determine which cryptographic operations will be applied to which messages and submessages. For instance, protecting the submessages with :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION` requires more operations than protecting the same submessages with :xmlval:`SIGN`. It is also important to see what you protect. For example, if you set :xmltag:`payload_protection_kind`, :xmltag:`metadata_protection_kind`, and :xmltag:`rtps_protection_kind` to :xmlval:`ENCRYPT` in a reliable |TOPIC|, every sample that your |DW| publishes will be encrypted three times; and every :submsg:`HEARTBEAT` and every :submsg:`ACKNACK` sent for that |TOPIC| will be encrypted twice. Hence, one of the major performance implications with respect to security is the protection kinds set in your |GovernanceFile|. For best performance, adjust your |GovernanceFile| to set the levels of protection that best fits your use case. Interaction Between the Security Plugins and Batching QoS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enabling security may also affect the throughput of your system in some scenarios. Assume that you have a reliable writer that sends small samples with a high frequency. You only want to protect the payload, so you decide to use payload protection. This protection is friendly to repairs: since the protection is applied to the sample before it is put in the |DW|'s queue, the sample does not need to be signed or encrypted again to send a repair. However, sending many small samples on the network will cause a big overhead, so you decide to use batching. Maybe it is not evident, but in this case, the computational cost of protecting each sample is far beyond the cost of sending it. Since samples are still encrypted individually, batching will not provide the performance improvement that we may expect. Another solution in this case is to switch from |DataProtection| to |SubmsgProtection|. Even if additional submessages will be protected, you may get higher throughput because protecting a bigger message once is more efficient than protecting multiple small messages. Depending on your network's loss rate, this may also be true even if repairs are needed (note that submessages will be signed/encrypted every time they are sent with |SubmsgProtection|). Interaction Between the Security Plugins and Multicast ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Multicast does not interact with how many times cryptographic operations are called to protect data, but can help reduce the network usage. Unlike TLS or DTLS transports, which do not allow multicast at all, the Security Plugins can take advantage of multicast to boost the performance of your system. Using multicast along with the |SP| will provide a performance boost similar (or identical) to the one that you will have in an unsecure scenario. In general, when you enable security, each message is protected once (see :ref:`p3_advanced/design_considerations:Interaction with Asynchronous Publishing`). Then the protected message is delivered to the transport once per destination. When you enable multicast, the protected sample is sent once to the network, as if it were a single destination, and the network will propagate it to the actual recipients. This is a great performance improvement over TLS and DTLS, where each sample needs to be protected once per destination, then sent to each destination with multiple socket write operations. .. figure:: ../static/multicast.png :scale: 50% :name: Transport Security VS DDS Security :align: center Transport Security VS DDS Security Interaction with Reliability ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |DataProtection| does not interact with reliability since the protection occurs before putting the samples in the |DW|'s queue. Therefore, repairing or resending a sample does not require additional cryptographic operations when using |DataProtection|. In contrast, |SubmsgProtection| and |RTPSProtection| apply the cryptographic operation right before sending the sample to the transport. Therefore, repairing or resending a sample will require additional cryptographic operations, such as re-encrypting it. Scalability Considerations for Origin Authentication Protection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When you use :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`, a |RecSpecificMAC| is added to the message being protected. As an optimization, when using the |DP|, this MAC is the same for every matching |DR| within a remote |DP| (i.e., the number of MACs does not grow per |DR|, but per |DP|). Therefore, the higher the number of |DPs| in your system, the bigger your RTPS packets will be. For further details, see :ref:`p2_core/cryptography:Origin Authentication Protection Implications`. Interaction with Content Filtered Topics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For Writer-side filtering: if |DataProtection| is in use and set to :xmlval:`ENCRYPT`, the |DW|'s queue will have samples encrypted. This is done to avoid encrypting each time a sample is sent, such as for repairs. However, this comes with some drawbacks: to apply Writer-side filtering, the |DW| needs to decrypt the samples in its queue, see if they match the filter, then send the corresponding samples. This is only needed for historical data: live samples are filtered before encrypting (i.e., which locators the sample will be sent to is decided before encrypting). Interaction with Topic Queries ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When you enable |DiscoveryProtection| for a |TOPIC| (by setting :xmltag:`enable_discovery_protection` to :xmlval:`TRUE`), TopicQuery requests related to that |TOPIC| will be exchanged through the Builtin Secure Service Request Topic. |SubmsgProtection| is applied to this |TOPIC|, at the level defined by the :xmltag:`discovery_protection_kind` |GovRule| (see :ref:`p2_core/cryptography:Builtin Secure Discovery Endpoints`). Protecting TopicQuery requests is needed in order not to leak information about your |TOPIC|. For example, in a hospital scenario, if you request information about a particular patient and the request was not protected, the patient name could be leaked. For further information on the overhead produced by this kind of protection, refer to :ref:`p3_advanced/design_considerations:Submessage Protection`. Interaction with Asynchronous Publishing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In general, the following sequence of events is used to protect-then-send a message to multiple destinations: #. Serialize the RTPS message with all its submessages. #. Only when using |SubmsgProtection| or RTPS Protection: Apply the cryptographic operations to protect the message with the configured level of protection. #. Send the protected RTPS message to multiple destinations. When you enable the Asynchronous Publishing feature (see :link_um:`ASYNCHRONOUS_PUBLISHER QosPolicy (DDS Extension) in the Core Libraries User's Manual `) in the Core Libraries User's Manual`), all this processing is done independently for each destination. This is required to support mechanisms such as flow controllers. Therefore, when Asynchronous Publishing is enabled, sending a message to multiple destinations will require the following steps for each destination: #. Serialize the RTPS message with all its submessages. #. Only when using Submessage Protection or RTPS Protection: Apply the cryptographic operations to protect the message with the configured level of protection. #. Send the protected RTPS message to a single destination. As you can see, the latter case requires more cryptographic operations. When you enable |DataProtection|, you need to increase :link_um:`DDS_FlowControllerTokenBucketProperty_t::bytes_per_token ` to include the overhead described in :ref:`p3_advanced/design_considerations:Serialized data protection` if you want to publish samples at the same frequency. Interaction with Compression ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When compression and |DataProtection| are enabled, compression will take place first, then the sample will be protected and stored in the |DW|'s Queue. The combination of compression, batching and |DataProtection| is not supported. When using batching, compression is applied to the batch, while |DataProtection| is applied to each of the batch samples (as explained in :ref:`p2_core/cryptography:Serialized data protection`). Hence, the compression ratio of the encrypted batch usually results in an expansion of the data instead of a reduction of it. Therefore this combination is not supported and will result in a |DW| creation error. To protect compressed batches, you can use RTPS Message Protection or |SubmsgProtection| instead, since either of these options will apply protection after the batch has been compressed. Keep in mind that both compression and protection add a significant CPU overhead with performance penalties to consider, so they only make sense under specific scenarios. Interaction with CRC ^^^^^^^^^^^^^^^^^^^^ The CRC extension allows you to detect packet corruption in RTPS messages by computing a 4-byte CRC over the DDS RTPS message (including the RTPS Header) and sending it as a new RTPS CRC32 submessage (see :link_um:`WIRE_PROTOCOL QosPolicy (DDS Extension) in the Core Libraries User's Manual `). The |SP| use 16-byte MACs to detect unexpected modifications on the received messages (see :ref:`p2_core/cryptography:Cryptography`). Note that the |SP| rely on the transport to detect and discard corrupted messages. Therefore, if the Cryptography plugin cannot validate a MAC upon a message reception, it will consider that the message was tampered with, compromising its integrity. This is a more secure approach and also discards corrupted messages. Note that combining CRC with the Security Plugins is not a supported configuration and may cause unexpected behavior. Interaction with Transport UDPv4_WAN ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When using HMAC-Only Mode, the value of :property:`hmac_only.cryptography.key` is used to protect UDP WAN binding pings. When not using HMAC-Only Mode, you may set an optional property called :property:`cryptography.rtps_protection_key` to specify a pre-shared key that is used to protect UDP WAN binding pings. See :numref:`RTI Security Plugins Properties for Configuring Cryptography` and :numref:`Properties for Configuring HMAC-Only Mode` for more details.