arkavo-org / arkavo-org/OpenTDFKit

Developer Experience Improvements for StandardTDF Encryption/Decryption

Open
#24 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Swift
Stars
1
Forks
1
Avg merge
9d 4h
Merged PRs (30d)
1

Description

## Summary

While integrating OpenTDFKit for encrypting user content as TDF files, I encountered several areas where developer experience could be improved, particularly around StandardTDF encryption/decryption workflows.

## Current Implementation Challenges

### 1. **Key Unwrapping After KAS Rewrap**

The `KASRewrapClient.rewrapStandardTDF` method returns `StandardTDFKASRewrapResult` with wrapped keys, but there's no clear documentation or helper method for unwrapping these keys to obtain the symmetric key.

**Current Code:**
```swift
let rewrapResult = try await rewrapClient.rewrapStandardTDF(
manifest: container.manifest,
clientPublicKeyPEM: clientPublicKeyPEM
)

// How to unwrap rewrapResult.wrappedKeys to get SymmetricKey?
let (_, rewrappedKeyData) = rewrapResult.wrappedKeys.first!
// Need guidance on proper ECDH key derivation here
let symmetricKey = SymmetricKey(data: rewrappedKeyData) // Is this correct?
```

**Suggested Improvement:**
- Add a helper method or documentation explaining the key derivation process
- Example: `StandardTDFCrypto.deriveSymmetricKey(from: rewrappedKeyData, using: clientPrivateKey)`

### 2. **StandardTDFDecryptor Limitations**

The `StandardTDFDecryptor` has methods for file-based decryption but lacks a convenient end-to-end method that handles KAS rewrap automatically.

**Current Options:**
- `decryptFile(inputURL:outputURL:symmetricKey:)` - Requires pre-obtained symmetric key
- `decryptFile(inputURL:outputURL:privateKeyPEM:)` - Works with local private key but not KAS

**Suggested Improvement:**
Add a method that handles the full KAS rewrap flow:
```swift
public func decryptFile(
inputURL: URL,
outputURL: URL,
kasURL: URL,
oauthToken: String
) async throws

// Or even simpler:
public func decrypt(
container: StandardTDFContainer,
kasClient: KASRewrapClient
) async throws -> Data
```

### 3. **KAS Public Key Fetching**

Fetching the KAS public key requires manual URL construction and JSON parsing. This is a common operation that could be simplified.

**Current Code:**
```swift
let url = URL(string: "\(kasEndpoint)/v2/kas_public_key")!
let (data, _) = try await URLSession.shared.data(from: url)
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
let publicKey = json["publicKey"] as? String
```

**Suggested Improvement:**
Add a static helper method:
```swift
public extension StandardTDFKasInfo {
static func fetchPublicKey(from kasURL: URL) async throws -> String
}
```

### 4. **DER to PEM Conversion**

Converting key representations for KAS is a common need but not provided by the library.

**Current Code:**
```swift
private func convertDERToPEM(_ derData: Data, type: String) throws -> String {
let base64 = derData.base64EncodedString(options: [.lineLength64Characters, .endLineWithLineFeed])
return "-----BEGIN \(type)-----\n\(base64)-----END \(type)-----\n"
}
```

**Suggested Improvement:**
Add to StandardTDFCrypto or a KeyConversion utility:
```swift
public extension StandardTDFCrypto {
static func pemRepresentation(of publicKey: P256.KeyAgreement.PublicKey) -> String
}
```

### 5. **Documentation Gaps**

**Missing Documentation:**
- End-to-end example of StandardTDF encryption with KAS
- Complete decrypt workflow including KAS rewrap
- Key derivation process after rewrap
- Policy structure examples with real-world use cases (e.g., user access control)

**Suggested Additions:**
- Add "Getting Started" guide for StandardTDF with KAS
- Document the full encrypt/decrypt cycle
- Include code examples in README
- API documentation for `StandardTDFKASRewrapResult`

### 6. **Policy Builder Ergonomics**

Creating policy JSON manually is error-prone and verbose.

**Current Code:**
```swift
let policyJSON = """
{
"uuid": "\(UUID().uuidString)",
"body": {
"dataAttributes": [],
"dissem": ["\(ownerId)"]
}
}
""".data(using: .utf8)!

let policy = try StandardTDFPolicy(json: policyJSON)
```

**Suggested Improvement:**
Add a policy builder:
```swift
let policy = StandardTDFPolicy.Builder()
.withUUID(UUID().uuidString)
.withDissemination([ownerId])
.withDataAttributes([])
.build()
```

## Suggested New APIs

### High-Level Encryption/Decryption

```swift
// Simplified encryption/decryption client
public struct StandardTDFClient {
public init(kasURL: URL, oauthToken: String)

public func encrypt(
plaintext: Data,
policy: StandardTDFPolicy,
mimeType: String?
) async throws -> StandardTDFContainer

public func decrypt(
container: StandardTDFContainer
) async throws -> Data
}
```

### Key Management Helpers

```swift
public extension StandardTDFCrypto {
// Unwrap symmetric key after KAS rewrap
static func unwrapSymmetricKey(
rewrappedKey: Data,
clientPrivateKey: P256.KeyAgreement.PrivateKey,
kasPublicKey: P256.KeyAgreement.PublicKey?
) throws -> SymmetricKey
}
```

## Implementation Context

**Use Case:** iOS app encrypting user-generated content as TDF files
- Files stored locally in Documents directory
- Shared via iOS share sheet or web links
- iOS 18.0+ deployment target

**Current Status:** Successfully building and integrating, but required several workarounds and assumptions about key derivation.

## Priority

**Medium-High** - These improvements would significantly reduce integration friction for new OpenTDFKit users.

## Workarounds Applied

1. Manual key unwrapping (may be incorrect for production)
2. Custom KAS public key fetching
3. Custom DER-to-PEM conversion
4. Manual policy JSON construction
5. Direct use of `KASRewrapClient` instead of higher-level APIs

## Additional Context

The library is very powerful and well-structured at the low level, but lacks some convenience APIs for common workflows. Adding these would make OpenTDFKit more accessible to developers who want secure TDF encryption without deep cryptographic knowledge.

Thank you for maintaining this library! Happy to contribute PRs for any of these improvements if there's interest.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing KASRewrapClient.rewrapStandardTDF, StandardTDFDecryptor, StandardTDFKasInfo, StandardTDFCrypto, and StandardTDFPolicy. The issue spans key derivation, decryption, key conversion, documentation, and policy construction, so first narrow it to one agreed improvement; done should be defined by the selected API or documentation outcome.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
cryptography, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.