Skip to content

Collection Encryption

Tayra supports encrypting collections of personal data. When a property marked with [PersonalData] is a List<string>, string[], or other supported collection type, Tayra encrypts each element individually. This is useful for entities that store multiple PII values in a single field, such as phone numbers, email aliases, medical allergies, or previous addresses.

Defining Collection PII

Mark collection properties with the [PersonalData] attribute, the same way you mark scalar string properties. Tayra detects the collection type automatically and encrypts each element:

cs
public class PatientRecord
{
    [DataSubjectId(Prefix = "patient-")]
    public Guid PatientId { get; set; }

    [PersonalData]
    public string FullName { get; set; } = "";

    [PersonalData]
    public List<string> Allergies { get; set; } = new();

    [PersonalData]
    public string[] PreviousSurnames { get; set; } = Array.Empty<string>();

    public string Department { get; set; } = "";
}
anchor

In the example above:

  • Allergies is a List<string> -- each allergy is encrypted individually
  • PreviousSurnames is a string[] -- each surname is encrypted individually
  • FullName is a regular string -- encrypted as usual
  • Department has no attribute -- left untouched

Per-Element Encryption

Each element in the collection is encrypted independently with the same key (derived from the [DataSubjectId]). This means:

  • Individual elements can be added or removed without re-encrypting the entire collection
  • Each element has its own nonce (initialization vector), so identical plaintext values produce different ciphertext
  • The collection size is preserved -- a list with 3 elements before encryption still has 3 elements after
csharp
// Before encryption
patient.Allergies = new List<string> { "Penicillin", "Peanuts", "Latex" };

// After encryption — 3 Base64-encoded ciphertext strings
patient.Allergies = new List<string>
{
    "AQzR4x5k...",  // Encrypted "Penicillin"
    "AQnT7y2m...",  // Encrypted "Peanuts"
    "AQ8pL9dw...",  // Encrypted "Latex"
};

Supported Collection Types

The following collection types are supported for [PersonalData] encryption:

TypeEncryptionDecryptionNotes
List<string>In-place mutationIn-place mutationElements are replaced with encrypted/decrypted values
string[]In-place mutationIn-place mutationArray elements are replaced directly
IList<string>In-place mutationIn-place mutationWorks via the IList<string> interface

Crypto-Shredding with Collections

When the encryption key is deleted (crypto-shredding), collection elements follow the same rules as scalar fields:

  • If partial redaction is configured, each element's embedded redacted value is returned
  • Otherwise, each element is replaced with an empty string ("")
csharp
// After crypto-shredding (key deleted)
patient.Allergies = new List<string> { "", "", "" };

Partial Redaction

Collection elements support the same partial redaction modes as scalar fields. Configure redaction on the [PersonalData] attribute:

csharp
public class ContactInfo
{
    [DataSubjectId]
    public Guid SubjectId { get; set; }

    [PersonalData(Masking = MaskingStrategies.MaskAfter, MaskingParameter = 3)]
    public List<string> EmailAddresses { get; set; } = new();
}

After crypto-shredding, each email would retain its first 3 characters:

"jan*****" // was "jane@example.com"
"bob*****" // was "bob@work.org"

Limitations

  • Only string element types are supported for collection encryption. Collections of non-string types (e.g., List<int>, List<DateTime>) must use [SerializedPersonalData] on the property with a companion byte[] field instead.
  • Null elements in a collection are skipped during encryption and decryption. They remain null in the collection.
  • Immutable collections (e.g., IReadOnlyList<string>, ImmutableList<string>) are not supported because Tayra modifies elements in-place. Use List<string> or string[] instead.
  • Deep collections (collections of objects with [DeepPersonalData]) are supported -- Tayra will recursively encrypt PII fields on each element. The element objects must have their own [DataSubjectId] or inherit the parent's key context.

Performance

Collection encryption processes elements sequentially. For very large collections (thousands of elements), the encryption time scales linearly. If performance is a concern, consider batching large collections or encrypting them as a single serialized blob with [SerializedPersonalData].

See Also