[PersonalData]
The [PersonalData] attribute marks a string property as containing personal data that should be encrypted. When EncryptAsync is called, the field's plaintext value is replaced with Base64-encoded AES-256-GCM ciphertext. When DecryptAsync is called, the original value is restored -- unless the encryption key has been deleted (crypto-shredded), in which case a replacement value is returned.
Basic Usage
Apply [PersonalData] to any string property alongside a [DataSubjectId] on the same class:
public class ContactInfo
{
[DataSubjectId]
public Guid UserId { get; set; }
[PersonalData]
public string FirstName { get; set; } = "";
[PersonalData]
public string LastName { get; set; } = "";
[PersonalData]
public string PhoneNumber { get; set; } = "";
}All three fields (FirstName, LastName, PhoneNumber) will be encrypted using the key derived from UserId.
Custom Mask Values
The MaskValue property specifies what value is returned when the encryption key has been deleted:
public class UserAccount
{
[DataSubjectId]
public Guid Id { get; set; }
[PersonalData(MaskValue = "[deleted user]")]
public string DisplayName { get; set; } = "";
[PersonalData(MaskValue = "deleted@example.com")]
public string Email { get; set; } = "";
[PersonalData(MaskValue = "000-00-0000")]
public string TaxId { get; set; } = "";
}After crypto-shredding:
DisplayNamereturns"[deleted user]"Emailreturns"deleted@example.com"TaxIdreturns"000-00-0000"
If MaskValue is not set, the default mask value for string fields is an empty string ("").
Groups
The Group property links a [PersonalData] field to a specific [DataSubjectId]. This enables multi-key scenarios where different fields on the same entity use different encryption keys:
public class PatientRecord
{
[DataSubjectId(Group = "medical")]
public Guid PatientId { get; set; }
[PersonalData(Group = "medical")]
public string Diagnosis { get; set; } = "";
[PersonalData(Group = "medical")]
public string Treatment { get; set; } = "";
/// <summary>
/// Not in the "medical" group — uses a separate key.
/// </summary>
[DataSubjectId]
public Guid RecordId { get; set; }
[PersonalData]
public string PatientName { get; set; } = "";
}In this example:
DiagnosisandTreatmentare encrypted with the key derived fromPatientId(group"medical").PatientNameis encrypted with the key derived fromRecordId(default group).- Shredding the
"medical"group key destroys only the medical data. The patient's name remains decryptable.
Properties Reference
| Property | Type | Default | Description |
|---|---|---|---|
Group | string? | null | Links this field to a [DataSubjectId] with the same group name. Fields without a group use the default (ungrouped) data subject ID. |
MaskValue | string? | null | Value returned after crypto-shredding. Defaults to "" for strings if not specified. |
Masking | string? | null | Partial masking strategy. When set (using a MaskingStrategies constant), a masked version of the value is embedded at encrypt time and returned after shredding instead of MaskValue. |
MaskingParameter | int | 0 | Mode-specific parameter. For MaskAfter, the number of leading characters to preserve. For MaskBefore, the number of trailing characters. |
Masking Strategies
MaskingStrategies Constant | Effect | Example Input | Example Output |
|---|---|---|---|
(not set / null) | No masking; uses MaskValue | -- | -- |
MaskAfter | Keep first N characters, mask the rest | "Jane Doe" (N=2) | "Ja******" |
MaskBefore | Keep last N characters, mask the rest | "Jane Doe" (N=3) | "*****Doe" |
MaskEmailDomain | Keep local part, mask domain | "jane@example.com" | "jane@***.***" |
Masking vs. MaskValue
When Masking is set to a MaskingStrategies constant, the masked value is embedded in the ciphertext at encryption time. After crypto-shredding, the masked value is returned instead of the MaskValue string. This allows you to retain partial information (e.g., masked email) while still being GDPR-compliant.
Supported Types
[PersonalData] is designed for string properties. For non-string types (int, DateTime, decimal, etc.), use [SerializedPersonalData] instead.
Tayra also supports string collections (List<string>, string[], IList<string>, IReadOnlyList<string>, ICollection<string>). Simply apply [PersonalData] to the collection property and each element will be individually encrypted.
See Also
[DataSubjectId]-- How encryption keys are derived[SerializedPersonalData]-- For non-string types- Getting Started -- End-to-end tutorial
- Attributes Overview -- All four attributes at a glance
