Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions concepts/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ While encryption protects confidentiality, it doesn't inherently prevent undetec
* **Purpose:** To allow recipients to verify that the encrypted payload has not been altered since its creation. This is especially critical for streamed data.
* **Mechanism:**
1. **Segmentation:** The plaintext payload is processed in chunks (segments).
2. **Segment Hashing/Tagging:** As each segment is encrypted (using AES-GCM, for example), a cryptographic integrity tag (like a GMAC) is generated for that encrypted segment using the *payload encryption key*. This tag is stored (as `hash`) in the corresponding [Segment Object](../schema/OpenTDF/integrity_information.md#encryptioninformationintegrityinformationsegment).
3. **Root Signature:** All the individual segment tags/hashes are concatenated in order. A final HMAC (e.g., HMAC-SHA256) is calculated over this concatenated string of hashes, again using the *payload encryption key*. This result is stored as the `rootSignature.sig`.
* **Result:** Any modification to even a single bit of the encrypted payload will invalidate the integrity tag of the affected segment *and* consequently invalidate the final `rootSignature`. During decryption, the receiving client MUST verify the integrity tag of each segment and the overall `rootSignature`. Failure indicates tampering.
2. **Segment Tagging (GMAC for AES-GCM):** For `method.algorithm = AES-256-GCM`, the segment `hash` is the AEAD authentication tag (GMAC) produced during encryption of that segment. It is computed with the payload key, the per-segment nonce, and any AAD, and stored as Base64 in the Segment Object.
3. **Root Signature (HS256):** Concatenate the raw bytes of each segment tag in order (Base64-decode each `segments[i].hash` and concatenate). Compute `HMAC-SHA256` over that byte stream using the payload key, then Base64-encode the result as `rootSignature.sig`.
4. **Nonce Requirement:** For streamable AES-GCM, each segment MUST use a unique nonce. The derivation and encoding MUST be specified by the encryption method. Reuse is catastrophic.
* **Result:** Any modification to even a single bit of the encrypted payload will invalidate the integrity tag of the affected segment *and* consequently invalidate the final `rootSignature`. During decryption, the receiving client MUST verify each segment's AEAD tag and the overall `rootSignature`. Failure indicates tampering.

**Note on plaintext payloads:** `payload.isEncrypted=false` is reserved for future use; integrity rules for plaintext payloads are out of scope.

## 3. Policy Binding

Expand Down Expand Up @@ -53,4 +56,4 @@ These mechanisms work together:
* **Policy Binding** ensures the access policy cannot be decoupled from the key access grant for a specific KAS.
* **Key Splitting** enforces multi-party authorization, preventing single points of failure or compromise for key access.

This layered approach provides robust, data-centric security and tamper evidence for data protected by OpenTDF.
This layered approach provides robust, data-centric security and tamper evidence for data protected by OpenTDF.
12 changes: 7 additions & 5 deletions schema/OpenTDF/integrity_information.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ The `integrityInformation` object, nested within [`encryptionInformation`](./enc

| Parameter | Type | Description | Required? |
| --------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| rootSignature | Object | Contains a cryptographic signature or HMAC over the combined integrity hashes of all segments, providing overall payload integrity. | Yes |
| rootSignature | Object | Contains a cryptographic integrity value over the combined segment hashes/tags, providing overall payload integrity. For `alg=HS256`, this is an HMAC. | Yes |
| rootSignature.alg | String | Algorithm used for the rootSignature.sig. HS256 (HMAC-SHA256 using the payload key) is commonly used. | Yes |
| rootSignature.sig | String | The Base64 encoded signature or HMAC value. Calculated over the concatenation of all segment hashes/tags in order. E.g., Base64(HMAC-SHA256(PayloadKey, Concat(SegmentHash1, SegmentHash2, ...))). | Yes |
| segmentHashAlg | String | The algorithm used to generate the hash for each segment in the segments array. GMAC (using the AES-GCM payload key) is commonly used when method.algorithm is AES-256-GCM. | Yes |
| rootSignature.sig | String | The Base64-encoded integrity value. For `alg=HS256`, this is `Base64(HMAC-SHA256(PayloadKey, Concat(bytes(Hash1), bytes(Hash2), ...)))`, where `bytes(HashN)` are the Base64-decoded segment hashes in order. | Yes |
| segmentHashAlg | String | The algorithm used to generate the hash for each segment in the segments array. For `AES-256-GCM`, `GMAC` (the AEAD tag) is used. | Yes |
| segments | Array | An array of [Segment Objects](#encryptionInformation.integrityInformation.segment), one for each chunk of the payload if method.isStreamable is true. Order MUST match payload order. | Yes |
| segmentSizeDefault | Number | The default size (in bytes) of the plaintext payload segments. Allows omitting segmentSize in individual segment objects if they match this default. | Yes |
| encryptedSegmentSizeDefault | Number | The default size (in bytes) of the encrypted payload segments (including any authentication tag overhead, like from AES-GCM). Allows omitting encryptedSegmentSize in segments. | |
Expand All @@ -43,6 +43,8 @@ Object containing integrity information about a segment of the payload, includin

|Parameter|Type|Description|
|---|---|---|
|`hash`|String|A hash generated using the specified `segmentHashAlg`.<br/><br/> `Base64.encode(HMAC(segment, payloadKey))`|
|`hash`|String|A Base64-encoded authentication tag generated using the specified `segmentHashAlg`. For `GMAC`, this is the AES-GCM tag produced during encryption of the segment with the payload key, the per-segment nonce, and any AAD.|

**Nonce derivation (AES-GCM, streamable):** Each segment must use a unique nonce; the derivation and encoding MUST be specified by the encryption method. Without a defined nonce scheme, GMAC verification is undefined.
|`segmentSize`|Number|The size of the segment. This field is optional. The size of the segment is inferred from 'segmentSizeDefault' defined above, but in the event that a segment were modified and re-encrypted, the segment size would change.|
|`encryptedSegmentSize`|Number|The size of the segment (in bytes) after the payload segment has been encrypted.|
|`encryptedSegmentSize`|Number|The size of the segment (in bytes) after the payload segment has been encrypted.|
2 changes: 1 addition & 1 deletion schema/OpenTDF/json-schema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
"type": "number"
},
"segmentHashAlg": {
"description": "Algorithm used to generate segment hashes",
"description": "Algorithm used to generate segment hashes (e.g., GMAC for AES-GCM AEAD tags)",
"type": "string"
},
"segments": {
Expand Down
2 changes: 1 addition & 1 deletion schema/OpenTDF/method.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ The `method` object, nested within [`encryptionInformation`](./encryption_inform
| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| algorithm | String | The symmetric encryption algorithm used. AES-256-GCM is the recommended and commonly implemented algorithm. | Yes |
| isStreamable | Boolean | Indicates if the payload was encrypted in segments suitable for streaming decryption. If true, [integrityInformation](./integrity_information.md) MUST contain segment details. | Yes |
| iv | String | The Base64 encoded Initialization Vector (IV) used with the symmetric algorithm. MUST be unique for each TDF encrypted with the same key. For AES-GCM, typically 12 bytes (96 bits). | Yes |
| iv | String | The Base64 encoded Initialization Vector (IV) used with the symmetric algorithm. MUST be unique for each TDF encrypted with the same key. For AES-GCM, MUST be 12 bytes (96 bits). | Yes |