AI agents: use the documentation index at llms.txt to locate machine-readable pages. This section is indexed by https://docs.particular.net/samples/llms.txt. The markdown version of this page is served as plain text. An MCP server at /mcp serves the same content via the search_docs and read_doc tools; it is read-only and needs no credentials. Markdown versions of documentation pages are available by appending .md to the page URL. Directory URLs use index.md. They are served as text/plain because some retrieval backends reject text/markdown.

Unobtrusive property encryption

NuGet Package:
NServiceBus.Encryption.MessageProperty 6.x
Target Version:
NServiceBus 10.x

This sample demonstrates how to use conventions to encrypt and decrypt specific properties of a message as it passes through the pipeline.

Running the solution starts two console applications:

  1. Endpoint1 encrypts a message and sends it
  2. Endpoint2 receives the encrypted message and decrypts it.

Endpoint1 output

MessageWithSecretData sent.

Endpoint2 output

I know the secret - it's 'betcha can't guess my secret'
SubSecret: My sub secret
CreditCard: 312312312312312 is valid to 3/11/2015 5:21:59 AM
CreditCard: 543645546546456 is valid to 3/11/2016 5:21:59 AM

Code walk-through

Message contract

The Shared project contains MessageWithSecretData.cs, which defines the message contract:

// Note all the properties to encrypt start with "Encrypted"
public class MessageWithSecretData
{
    public string EncryptedSecret { get; set; }
    public MySecretSubProperty SubProperty { get; set; }
    public List<CreditCardDetails> CreditCards { get; set; }
}

public class MySecretSubProperty
{
    public string EncryptedSecret { get; set; }
}

public class CreditCardDetails
{
    public DateTime ValidTo { get; set; }
    public string EncryptedNumber { get; set; }
}

Encryption configuration

Encryption is enabled by calling an extension method in Program.cs for both Endpoint1 and Endpoint2:

endpointConfiguration.ConfigurationEncryption();

The extension method is implemented in Shared/EncryptionExtensions.cs:

public static void ConfigurationEncryption(this EndpointConfiguration endpointConfiguration)
{
    var encryptionService = new AesEncryptionService(
        encryptionKeyIdentifier: "2015-10",
        key: Convert.FromBase64String("v96c7+e1aqFeNhMdZneHAQITEcgJu1z3ENSFUIr+FoM="));
    endpointConfiguration.EnableMessagePropertyEncryption(encryptionService,
        encryptedPropertyConvention: info => info.Name.StartsWith("Encrypted"));
}

The message on the wire

The serialized message content can be seen by running Endpoint1 without running Endpoint2.

Messages are queued in the .learningtransport folder next to the solution. The message will be contained in a file in the Samples.Encryption.Endpoint2 sub-folder with the following content (XML namespaces removed for clarity):

<?xml version="1.0" encoding="UTF-8"?>
<MessageWithSecretData>
   <Secret>
      <EncryptedValue>
         <EncryptedBase64Value>VOQk8pvlMdpdAgQiJldg2WZQCL86FxFMEd0VsTydOSw=</EncryptedBase64Value>
         <Base64Iv>4OnlFC1WyhTmkDLyfOdnYQ==</Base64Iv>
      </EncryptedValue>
   </Secret>
   <SubProperty>
      <Secret>
         <EncryptedValue>
            <EncryptedBase64Value>uEjQePtNlhkWEr5QHgiLbA==</EncryptedBase64Value>
            <Base64Iv>kh5C9W9picaOZ5dhz4adlA==</Base64Iv>
         </EncryptedValue>
      </Secret>
   </SubProperty>
   <CreditCards>
      <CreditCardDetails>
         <ValidTo>2024-03-08T21:08:34.091063Z</ValidTo>
         <Number>
            <EncryptedValue>
               <EncryptedBase64Value>Iv621YNDox3pd1zIbkeRrA==</EncryptedBase64Value>
               <Base64Iv>VPrVGB888YmKhi8lgkNFtg==</Base64Iv>
            </EncryptedValue>
         </Number>
      </CreditCardDetails>
      <CreditCardDetails>
         <ValidTo>2025-03-08T21:08:34.093907Z</ValidTo>
         <Number>
            <EncryptedValue>
               <EncryptedBase64Value>WY69+QzkqqKJ6UYCemShUg==</EncryptedBase64Value>
               <Base64Iv>BFLz5jz0DdhJNK01MFrMmA==</Base64Iv>
            </EncryptedValue>
         </Number>
      </CreditCardDetails>
   </CreditCards>
</MessageWithSecretData>