Dynamic KAS selection Mappings β
What is KAS Mapping? β
The KAS Mapping is an optional configuration in your SDSDK instance.
It allows for the dynamic selection of one or more Key Access Servers (KAS) during encryption based on dataAttributes.
Instead of always encrypting with the full configured kasList, the SDK evaluates mapping rules and determines which KAS should be used to protect the Data Encryption Key (DEK), either entirely or as cryptographic splits of it.
ππ Practical example: Protecting confidential project documents β
A company needs to encrypt confidential documents before storing them or sharing them with external partners.
Different rules apply depending on:
- Which partners are allowed to access the document
- Which internal department must authorize the access to the document
Two types of access controls are required:
| Rule | Security behavior |
|---|---|
| Sharing with partners | Any authorized partner can decrypt the document |
| Internal authorization | Multiple internal departments must grant authorization |
To implement this, the SDK mapping uses:
- Permissive mappings β OR logic between partners
- Restrictive mappings β AND logic between internal authorities
KAS Infrastructure β
Each organization or internal authority operates its own Key Access Server.
| Organization | KAS |
|---|---|
| Internal Security Department | kas-security |
| Legal Department | kas-legal |
| Partner Company A | kas-partner-a |
| Partner Company B | kas-partner-b |
Mapping Configuration β
An SDSDK is configured as follows:
ts
const config: SdsdkConfiguration = {
defaultKasId: "kas-security",
kasList: [
{ id: "kas-security", protocols: [Protocol.Kas], url: "...", publicKey: {...} },
{ id: "kas-legal", protocols: [Protocol.Kas], url: "...", publicKey: {...} },
{ id: "kas-partner-a", protocols: [Protocol.Kas], url: "...", publicKey: {...} },
{ id: "kas-partner-b", protocols: [Protocol.Kas], url: "...", publicKey: {...} }
],
mappingSections: [
{
label: "document-access-rules",
mapping: [
{
attributeName: "sharedWith",
type: MappingItemType.Permissive,
attributeValues: [
{ value: "partner-a", kasIds: ["kas-partner-a"] },
{ value: "partner-b", kasIds: ["kas-partner-b"] },
{ value: "all-partners", kasIds: ["kas-partner-a", "kas-partner-b"] }
]
},
{
attributeName: "belongsTo",
type: MappingItemType.Restrictive,
attributeValues: [
{
value: "confidential-project",
kasIds: ["kas-security", "kas-legal"]
}
]
}
]
}
]
};Encryption Example β
A document belongs to a confidential project and can be shared with all partners.
ts
await sdsdk.encrypt({
data: documentBytes,
dataAttributes: [{ sharedWith: 'all-partners' }, { belongsTo: 'confidential-project' }],
protocol: Protocol.Kas,
});Resulting Encryption Model β
Mapping evaluation produces:
| Rule | Result |
|---|---|
| sharedWith: all-partners | permissive group β kas-partner-a OR kas-partner-b |
| belongsTo: confidential-project | restrictive β kas-security AND kas-legal |
The confidential document will be secured according to all these rules:

Security Implications β
This enforces the following rule:
( partner A OR partner B ) AND security AND legal
Meaning that:
- the document can be accessed by the authorized partner A or B
- but internal authorization from both departments is required
Mapping Configuration Structure β
Mapping is configured in SdsdkConfiguration:
typescript
{
defaultKasId: "...",
kasList: [...],
mappingSections: [
{
label: 'example-mapping',
mapping: [
{
attributeName: 'releasableTo',
type: MappingItemType.Permissive,
attributeValues: [
{ value: 'A-B', kasIds: ['kas-A', 'kas-B'] },
{ value: 'A', kasIds: ['kas-A'] },
{ value: 'B', kasIds: ['kas-B'] },
],
},
],
},
];
}The mapping is an item in the mappingSections list.
Each mapping item defines:
attributeName: the DataAttribute keytype: how matching KAS are split (permissiveorrestrictive)attributeValues: mapping between attribute value and KAS identifiers
β οΈ For the moment, only one mappingSection item is allowed in the mappingSections list. Each additional mappingSections item will cause an error. However, each section may contain multiple mapping items.
βοΈ How Mapping Is Evaluated (technical) β
During encryption:
- Data is encrypted via a DEK (Data Encryption Key).
- The SDK extracts eligible
dataAttributes(1-level object with string as value). - For each attribute, the SDK getsΒ all the matching mapping item and values.
- These matches allow to split the DEK in different splits (sDEKs), then encrypt each sDEK with one or more KAS, according to mapping.
- Encrypted sDEKs are stored in the produced ZTDF manifest.
-> If no mapping rule matches or if a dataAttribute value is not defined in the mapping, then encryption fails.
-> Identical KAS sets are automatically deduplicated. (["kas-A" OR "kas-B"] = ["kas-B" OR "kas-A"])
β οΈ After mapping resolution:
- Each selected KAS must support the requested encryption protocol.
- If not, encryption fails with a
KasSelectionError.
Mapping Modes β
Mapping supports two modes.
Permissive Mode (permissive) β
Permissive mode behaves like a logical OR.
Within a single split, the entire DEK is wrapped for each KAS. Any of those KAS can independently unwrap that DEK (logical OR inside the split).
Example β
An SDSDK instance with this mapping:
typescript
{
attributeName: "releasableTo",
type: MappingItemType.Permissive,
attributeValues: [
{ value: "A-B", kasIds: ["kas-A", "kas-B"] },
{ value: "B-C", kasIds: ["kas-B", "kas-C"] }
]
},
{
attributeName: "releasableTo2",
type: MappingItemType.Permissive,
attributeValues: [
{ value: "B-C", kasIds: ["kas-B", "kas-C"] }
]
}Encryption input:
Sdsdk.encrypt() is called with these data attributes in input:
typescript
dataAttributes: [{ releasableTo: 'A-B' }];Result:
- entire DEK is wrapped for:
- kas-A
- kas-B
Multiple permissive attributes β
Each matching attribute produces its own split.
Example:
Sdsdk.encrypt() is called with these data attributes in input:
typescript
dataAttributes: [{ releasableTo: 'A-B' }, { releasableTo2: 'B-C' }];If both match permissive rules:
Result:
- 2 independent encryption splits
- One split that can be decrypted by A OR B
- One split that can be decrypted by B OR C
β οΈ Note on multiple permissive attributes
In permissive mode, when several dataAttributes share the same attributeName, the SDK resolves each value and merges all mapped KAS into one combined split (logical OR) before generating the final encryption split. For example:typescriptdataAttributes: [{ releasableTo: 'A-B' }, { releasableTo: 'B-C' }];Will be interpreted with this result:
- 1 encryption split
- entire DEK is wrapped for:
- kas-A
- kas-B
- kas-C
Restrictive Mode (restrictive) β
Restrictive mode creates independent encryption splits per matching KAS.
Each matching KAS generates its own split & each resulting split protects a distinct cryptographic share of the DEK.
During the decryption, all shares are required to reconstruct the DEK
Example: β
An SDSDK instance with this mapping:
typescript
{
attributeName: "mission",
type: MappingItemType.Restrictive,
attributeValues: [
{ value: "alpha", kasIds: ["kas-A", "kas-B"] },
{ value: "beta", kasIds: ["kas-B", "kas-C"] }
]
}Encryption input:
Sdsdk.encrypt() is called with these data attributes in input:
typescript
dataAttributes: [{ mission: 'alpha' }];Result:
- The DEK is split into multiple cryptographic shares (SDEKs)
- One is encrypted by kas-A
- One is encrypted by kas-B
β οΈ Note on duplicated restrictive attributes
In restrictive mode, when different splits are encrypted by the same KAS, the SDSDK deduplicate these splits. For example, Sdsdk.encrypt() is called with these data attributes in input:
typescriptdataAttributes: [{ mission: 'ALPHA' }, { mission: 'BETA' }];Result in the following splits:
- ["kas-A"]
- ["kas-B"]
- ["kas-B"]
- ["kas-C"]
Which is simplified as:
- ["kas-A"]
- ["kas-B"]
- ["kas-C"]
Combining Permissive and Restrictive Rules β
An SDSDK instance with this mapping:
typescript
{
attributeName: "releasableTo",
type: MappingItemType.Permissive,
attributeValues: [
{ value: "A-B", kasIds: ["kas-A", "kas-B"] },
{ value: "B-C", kasIds: ["kas-B", "kas-C"] }
]
},
{
attributeName: "mission",
type: MappingItemType.Restrictive,
attributeValues: [
{ value: "alpha", kasIds: ["kas-A", "kas-B"] },
{ value: "beta", kasIds: ["kas-B", "kas-C"] }
]
}Permissive and restrictive attributes can be combined to define rules.
Example:
typescript
dataAttributes: [
{ releasableTo: 'A-B' }, // permissive β [kas-A, kas-B]
{ mission: 'alpha' }, // restrictive β [kas-A], [kas-B]
];Result:
- 3 independent encryption splits
- One split for A OR B
- One split for kas-A
- One split for kas-B
Just like before, identical KAS sets are automatically deduplicated:
dataAttributes: [ { releasableTo: 'A-B' }, // permissive β [kas-A, kas-B] { mission: 'alpha' }, // restrictive β [kas-A], [kas-B] { mission: 'beta' }, // restrictive β [kas-B], [kas-C] ];
Result in the following splits:
- ["kas-A"] OR ["kas-B"]
- ["kas-A"]
- ["kas-B"]
- ["kas-B"]
- ["kas-C"]
Which is simplified as:
- ["kas-A"] OR ["kas-B"]
- ["kas-A"]
- ["kas-B"]
- ["kas-C"]