Document: RFC-KEBAC-001
Category: Experimental
Status: Draft
Date: November 2025
Authors: The BeTTY Project Contributors
This document specifies an experimental access control mechanism for the Internet community and requests discussion and suggestions for improvements. Distribution of this memo is unlimited.
KEBAC (Keyed Encryption-Based Access Control) is a cryptographic access control system which relies on encryption for authorization and authentication, combined with access control lists (ACLs) and UNIX-style octal permissions.
In KEBAC, authorization is granted by encrypting content to a recipient's public key, and authentication is proven by successful decryption with the corresponding private key. This document describes the KEBAC model, its implementation within the BeTTY protocol, and security considerations for its deployment.
Traditional access control systems separate authentication (proving who you are) from authorization (what you're allowed to do). This separation requires maintaining permission databases, session tokens, and complex role hierarchies. KEBAC unifies these concepts through cryptography: if you can decrypt it, you can access it.
Modern distributed systems face several access control challenges:
KEBAC addresses these issues by:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Identity: A cryptographic keypair (public and private keys) representing a user, service, or group
Owner: The identity that created a resource and has ultimate control over it
Encryption: The process of rendering data unreadable without the corresponding private key
Public Key: The publicly distributed half of an asymmetric keypair
Private Key: The secret half of an asymmetric keypair, never transmitted
Signature: Cryptographic proof that data was created by a specific identity
PRPH: Poor Richard's Pseudo-Homomorphism - operations on encrypted data without full decryption
ACL: Access Control List - mapping of identities to permission levels
Octal: Base-8 numeric representation of permission bits (0-7)
KEBAC is built on three fundamental principles:
Axiom 1: Authorization Through Encryption
Authorization is granted by encrypting content to a recipient's public key. No separate permission grant is needed.
Axiom 2: Authentication Through Decryption
Authentication is proven by successful decryption. If you can decrypt the data, you are who you claim to be.
Axiom 3: No Passwords, No Sessions
The system never stores, transmits, or compares passwords. Sessions are unnecessary because every request is self-authenticating via signature.
These axioms have profound implications:
| Aspect | Traditional | KEBAC |
|---|---|---|
| Authentication | Password/token check | Signature verification |
| Authorization | Database lookup | Decryption capability |
| Session Management | Server-side sessions | Stateless (every request signed) |
| Permission Storage | Centralized database | Encrypted with content |
| Federation | Complex trust protocols | Public key distribution |
| Revocation | Permission table update | Key rotation + re-encryption |
KEBAC uses UNIX-style octal permissions (0-7) but redefines their meaning for distributed, federated systems:
| Bit | Value | Traditional | KEBAC Meaning |
|---|---|---|---|
| r | 4 | Read | Copy: Can decrypt and read content |
| w | 2 | Write | Update: Can modify the resource |
| x | 1 | Execute | Index: Can include in searches/indices |
Each permission level is the sum of its component bits:
| Octal | Binary | Perms | Meaning | Use Case |
|---|---|---|---|---|
| 0 | 000 | --- |
No access | Default for unauthenticated |
| 1 | 001 | --x |
Index only | Public search without read access |
| 2 | 010 | -w- |
Write only | Blind append (inbox, dead drop) |
| 3 | 011 | -wx |
Write + index | Public inbox (searchable but unreadable) |
| 4 | 100 | r-- |
Read/Copy only | Public readable, owner-only edit, MAY be forkable |
| 5 | 101 | r-x |
Read/Copy + index | Standard public content, MAY be forkable |
| 6 | 110 | rw- |
Read/Copy + write | Collaborative edit, not searchable, MAY be forkable |
| 7 | 111 | rwx |
Full access | Owner privileges |
Note: Type casting works as follows:
true MUST evaluate to 7 (full access).false or an empty string MUST evaluate to 0 (no access).Permissions are stored in the resource's metadata as an Access Control List (ACL):
{
"betty": {
"owner": "alice@betty.land",
"permissions": {
"@world": 5,
"@authenticated": 5,
"@staff": 7,
"bob@betty.land": 6,
"carol@betty.land": 4
}
}
}ACL Rules: 1. Owner automatically has full access (7) without being listed 2. Identities must exist in the PKI system 3. Groups (prefixed with @) expand to their members 4. More specific identities override less specific ones 5. Order of evaluation: specific identity → group → @authenticated → @world
@world: Everyone, including unauthenticated users (if content is not encrypted)
@authenticated: Any identity with a valid keypair
@group-name: Named groups defined in /system/@groups/
Example group definition:
{
"betty": {
"topic": "hash-of-group-name",
"owner": "admin@betty.land"
},
"content": {
"group": "@staff",
"display_name": "Staff Members",
"members": [
"alice@betty.land",
"bob@betty.land",
"carol@betty.land"
],
"admins": ["admin@betty.land"],
"encryption_key": "age1groupkey..."
}
}KEBAC's cryptographic requirements are not fixed on a particular standard. Keys must be able to provide both signing and encrypting capacities to each user. In the race between encryption and cracking, KEBAC wants you to choose the strongest available option and be able to rotate keys when needed.
Public keys are distributed through:
GET /api/v1/keys/<identity>Key distribution channels MUST be:
All operations MUST be signed by the requesting identity:
{
"routing": {
"from": "bob@betty.land",
"signatures": [
{
"identity": "bob@betty.land",
"algorithm": "ed25519",
"signature": "base64-encoded-signature",
"timestamp": "2025-11-16T10:00:00Z",
"salt": "random-unique-value"
}
]
}
}Signature Requirements:
After successful decryption, a decrypted document which is fully compliant with KEBAC's permissions system implements ACLs with octal permissions. Because KEBAC is designed for federated local-first systems, it has a different permissions model from UNIX's read/write/execute grants.
In KEBAC, permission grants are structured as follows:
Copy: the ability to decrypt messages. For implementing KEBAC, this means documents must be encrypted to the grantee's public key. Write: the ability to replace or append the document within the implementor's content management system. Index: the ability to include this document in indicies, e.g., make this document searchable independently from a users' copy or write privileges.
KEBAC permissions are enforced at multiple layers:
1. Cryptographic Layer
2. Storage Layer
3. Indexing Layer
4. Network Layer
Required For: Decrypting and viewing content
Servers do not need to "check" permissions. If the client has the private key corresponding to one of the encrypted symmetric keys, they can decrypt. Otherwise, they cannot.
Unauthenticated errorRequired For: Modifying the resource (upsert or append)
Write-Only Scenario (permission = 2):
Read-Write Scenario (permission = 6):
Required For: Including resource in search indices
Index-Only Scenario (permission = 1):
Read without Index (permission = 4):
KEBAC supports operations on encrypted data without full decryption through Poor Richard's Pseudo-Homomorphism (PRPH). For full details about PRPH, see the [NBSON-RFC].
PRPH, as the name suggests, is not a true homomorphic operation; instead, it uses a keymap to replace encrypted values within a document. Implementors MAY allow blind operations as follows:
Blind Append (permission = 2 or 3):
Blind Edit (permission = 2 with PRPH level 5):
Configuration: PRPH behavior controlled by nbson.prph_write setting (0-5).
Alternatively, true homomorphic encryption may be deployed in a substitute component for PRPH to provide equivalent functionality; such mathematics are beyond the scope of this RFC.
When a user has read permission (4) but NOT write permission (2), servers MAY allow forked writes.
This enables derivative works without permission, while the original remains immutable. Attribution remains automatic and provenance remains auditable.
abc123r-- not rw-)def456abc123 unchanged, and the forked document maintains provenanceConfiguration: Controlled by lakehouse.forked_write (boolean).
Groups can use symmetric keys for efficiency.
When membership changes, rotate keys: 1. Generate new group key 2. Re-encrypt all group content to new key 3. Distribute new key to current members 4. Archive old content encrypted to old key
Identities can create sub-keys for delegation. These sub-keys inherit permissions from the user's parent or previous identity. Sub-keys can be revoked independently, and enable least privilege access, perfect for temporary grants or limiting the cryptographic attack surface by using different keys to distribute interceptable encrypted data.
Implement time-limited access through scheduled key rotation:
access_expiry datesThe following examples use the BettyDoc format, which is a KEBAC-compliant implementation within the BeTTY protocol. See [BeTTY-Protocol-RFC] for more details.
Scenario: Blog post, documentation, announcement
{
"betty": {
"owner": "alice@betty.land",
"permissions": {
"@world": 5
}
}
}Behavior:
Scenario: Team wiki, shared project notes
{
"betty": {
"owner": "alice@betty.land",
"permissions": {
"@team": 7,
"@world": 1
}
}
}Behavior:
Scenario: Contact form, anonymous feedback
{
"betty": {
"owner": "alice@betty.land",
"permissions": {
"@world": 3
}
}
}Behavior:
Scenario: Whistleblowing, confidential submissions
{
"betty": {
"owner": "journalist@betty.land",
"permissions": {
"@world": 2
}
}
}Behavior:
Scenario: Private documents with controlled access
{
"betty": {
"owner": "bob@betty.land",
"permissions": {
"alice@betty.land": 4,
"carol@betty.land": 6
}
}
}Behavior:
Scenario: Academic lab with temporary members
{
"betty": {
"owner": "dr-smith@betty.land",
"permissions": {
"@research-group": 7,
"intern-jane@betty.land": 5
},
"access_expiry": {
"intern-jane@betty.land": "2025-12-31T23:59:59Z"
}
}
}Behavior:
KEBAC protects against:
Password theft: No passwords exist
Session hijacking: No sessions to hijack
Man-in-the-middle: Signatures prevent tampering
Server compromise: Encrypted data unreadable
Permission escalation: Cryptographically enforced
Replay attacks: Timestamps and nonces prevent replay
KEBAC does NOT protect against:
Endpoint compromise: If private key is stolen, attacker has access
Side-channel attacks: Implementation must use constant-time operations
Social engineering: Users must protect their private keys
Quantum computing: Current algorithms vulnerable to future quantum attacks, users must choose strong algorithms
Rubber hose cryptanalysis: Physical coercion can extract keys
Critical Requirements:
KEBAC implementations MUST support algorithm agility:
Future-Proofing:
KEBAC implementations SHOULD implement:
Data Privacy: Content encrypted at rest protects this data from server operators, allowing Torrent-like distributed hosting for files.
Metadata Privacy:
When KEBAC is implemented with [NBSON], each field is indivudally encryptable to a different key, which includes metadata.
Social Graph Privacy:
Implementors MAY store KEBAC operation logs to produce a tamper-evident audit trail:
{
"event": {
"from": "bob@betty.land",
"operation": "upsert",
"target": "betty://local/documents/abc123",
"signatures": [{
"identity": "bob@betty.land",
"algorithm": "ed25519",
"signature": "...",
"timestamp": "2025-11-16T10:00:00Z"
}]
}
}Audit Properties:
Clients MUST:
Clients MAY:
Servers MUST:
Servers SHOULD:
Servers MAY: - substitute true homomorphic encryption in place of PRPH
| Aspect | OAuth 2.0 | KEBAC |
|---|---|---|
| Token Type | Bearer tokens | Signatures |
| Session | Required | Stateless |
| Revocation | Token revocation | Key rotation |
| Federation | Complex flows | Public key distribution |
| Security | Token theft risk | No tokens to steal |
| Aspect | Kerberos | KEBAC |
|---|---|---|
| Tickets | Required | Not needed |
| KDC | Central authority | Distributed |
| Encryption | Symmetric keys | Asymmetric keys |
| Federation | Realm trusts | Public key trust |
| Complexity | High | Moderate |
| Aspect | RBAC | KEBAC |
|---|---|---|
| Permissions | Role tables | Encryption keys |
| Enforcement | Database lookup | Cryptographic |
| Federation | Difficult | Native |
| Revocation | Update DB | Re-encrypt |
| Auditability | Logs (mutable) | Signatures (immutable) |
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital Signature Algorithm (EdDSA)", RFC 8032, January 2017.
[Capability-Myths] Miller, M., "Capability Myths Demolished", 2003.
[BeTTY-Protocol-RFC] "The BeTTY Protocol", RFC-BETTY-001.
[NBSON-RFC] "NBSON Storage Format", NBSON-RFC-001.
KEBAC builds upon concepts from:
Public key cryptography pioneered by Diffie, Hellman, Rivest, Shamir, and Adleman
Plan 9 From Bell Labs and UNIX
Git and content-addressed storage with cryptographic verification
Phil Alden Robinson's Sneakers (1992), starring Donal Logue as mathematician Gunter Janek:
There exists an intriguing possibility for a far more elegant solution... we might induce homomorphisms from the principal ordinance of each of these fields...
Special thanks to cryptographers who made strong encryption accessible to all.
Note: this appendix uses document vocabulary from the [BeTTY Protocol], [BettyMsg/BettyDoc Standard] and pseudocode in Python.
1. Client generates Ed25519 keypair (signing)
2. Client generates X25519 keypair (encryption)
3. Client creates identity document:
{
"identity": "alice@betty.land",
"signing_key": "age1abc...",
"encryption_key": "age1xyz...",
"created": "2025-11-16T10:00:00Z"
}
4. Client signs document with private signing key
5. Client publishes to node at betty://betty.land/api/v1/keys/alice@betty.land
6. Node stores public keys (not private keys!)
1. Alice creates document:
{
"title": "Secret Plan",
"content": "The secret is..."
}
2. Alice specifies ACL:
{
"owner": "alice@betty.land",
"permissions": {
"bob@betty.land": 4
}
}
3. System generates random symmetric key K
4. System encrypts document with K → C
5. System encrypts K to Alice's public key → K_alice
6. System encrypts K to Bob's public key → K_bob
7. System stores:
{
"betty": {
"owner": "alice@betty.land",
"permissions": {
"bob@betty.land": 4
}
},
"meta": {
"encryption": {
"recipients": {
"alice@betty.land": K_alice,
"bob@betty.land": K_bob
}
}
},
"content": C
}
1. Bob requests document (signed request)
2. Node verifies Bob's signature → authenticated
3. Node returns encrypted document
4. Bob's client finds K_bob in recipients
5. Bob decrypts K_bob with his private key → K
6. Bob decrypts C with K → original document
7. Success! Bob can read (has permission 4)
1. Bob modifies document locally
2. Bob signs upsert request
3. Node verifies signature → authenticated as Bob
4. Node decrypts ACL (using Bob's key, since he has read access)
5. Node checks permissions: Bob has 4 (r--), needs 6 (rw-)
6. Node returns error:
{
"error": "Unauthorized",
"message": "Write permission required",
"current_permission": 4,
"required_permission": 6
}
Note: this example refers to [NBSON] and its use of Poor Richard's Pseudo-Homomorphism or PRPH, which uses keymaps to modify encrypted values without having to decrypt them. In NBSON, queue documents may be appended by adding a line to the end of the file, with individual encryption.
1. Carol creates message (not encrypted yet):
{
"from": "carol@betty.land",
"message": "Anonymous feedback here"
}
2. Carol encrypts message to inbox owner's public key → M_encrypted
3. Carol signs append request:
{
"routing": {
"from": "carol@betty.land",
"operation": "append",
"target": "betty://local/inbox/abc123",
"signatures": [...]
},
"payload": M_encrypted
}
4. Node verifies signature → authenticated as Carol
5. Node checks permissions: @world has 3 (-wx)
6. Node uses PRPH to append without decrypting existing content:
- Reads NBSON index line
- Locates append point
- Writes M_encrypted to queue
- Updates index
7. Success! Carol appended without reading
8. Alice (inbox owner) later reads:
- Decrypts entire queue with her private key
- Sees Carol's message and all others
Cause: Cannot decrypt document with available keys
{
"routing": {
"from": "system",
"to": "requesting-identity"
},
"meta": {
"tags": ["error", "authentication"]
},
"payload": {
"error": "Unauthenticated",
"message": "Cannot decrypt document with available keys",
"required": "Private key corresponding to one of the recipient public keys",
"available_recipients": [
"alice@betty.land",
"bob@betty.land"
]
}
}Scenarios:
Cause: Insufficient permissions for requested operation
{
"routing": {
"from": "system",
"to": "bob@betty.land"
},
"meta": {
"tags": ["error", "authorization"]
},
"payload": {
"error": "Unauthorized",
"message": "Insufficient permissions for operation",
"operation": "upsert",
"required_permission": 6,
"current_permission": 4,
"permission_breakdown": {
"read": true,
"write": false,
"index": false
},
"suggestion": "Request write access from owner or create forked copy"
}
}Scenarios:
Cause: Signature verification failed
{
"routing": {
"from": "system"
},
"meta": {
"tags": ["error", "authentication", "signature"]
},
"payload": {
"error": "SignatureInvalid",
"message": "Signature verification failed",
"identity": "bob@betty.land",
"signature_algorithm": "ed25519",
"possible_causes": [
"Message was tampered with",
"Wrong private key used for signing",
"Public key mismatch",
"Corrupted signature data"
]
}
}Cause: Request timestamp too old
{
"routing": {
"from": "system"
},
"meta": {
"tags": ["error", "replay-protection"]
},
"payload": {
"error": "TimestampExpired",
"message": "Request timestamp outside acceptable window",
"request_timestamp": "2025-11-15T10:00:00Z",
"server_time": "2025-11-16T10:00:00Z",
"max_age_seconds": 300,
"suggestion": "Synchronize system clock and retry"
}
}Cause: Required key not in PKI system
{
"routing": {
"from": "system"
},
"meta": {
"tags": ["error", "key-management"]
},
"payload": {
"error": "KeyNotFound",
"message": "Required public key not found in PKI",
"identity": "unknown@betty.land",
"key_type": "encryption",
"suggestion": "Ensure identity is registered at betty://betty.land/api/v1/keys/unknown@betty.land"
}
}Can user read document?
│
├─ Is user the owner?
│ └─ YES → Allow (owner always has full access)
│
├─ Can user decrypt ACL?
│ ├─ NO → Deny (Unauthenticated)
│ └─ YES → Continue
│
├─ User's permission value & 4 (read bit)?
│ ├─ NO → Deny (Unauthorized)
│ └─ YES → Allow
│
└─ Can user decrypt content?
├─ NO → Deny (Unauthenticated - key not in recipients)
└─ YES → Success!
Can user write (upsert) document?
│
├─ Is user the owner?
│ └─ YES → Allow
│
├─ Can user decrypt ACL?
│ ├─ NO → Deny (Unauthenticated)
│ └─ YES → Continue
│
└─ User's permission value & 2 (write bit)?
├─ NO → Check if forked writes enabled
│ ├─ NO → Deny (Unauthorized)
│ └─ YES & user has read (4)?
│ ├─ YES → Allow fork (new topic)
│ └─ NO → Deny (Unauthorized)
│
└─ YES → User's permission value & 4 (read bit)?
├─ NO → Deny (Upsert requires read+write, suggest append)
└─ YES → Allow
Can user append to document?
│
├─ Is user the owner?
│ └─ YES → Allow
│
├─ Can user decrypt ACL?
│ ├─ NO → Deny (Unauthenticated)
│ └─ YES → Continue
│
└─ User's permission value & 2 (write bit)?
├─ NO → Deny (Unauthorized)
└─ YES → Check PRPH configuration
│
├─ User's permission value & 4 (read bit)?
│ └─ YES → Allow (read+write)
│
└─ PRPH level >= 2 (blind-append)?
├─ YES → Allow (blind append)
└─ NO → Deny (Read required for append)
Can user add document to index?
│
├─ Is user the owner?
│ └─ YES → Allow
│
├─ Can user decrypt ACL?
│ ├─ NO → Deny (Unauthenticated)
│ └─ YES → Continue
│
└─ User's permission value & 1 (index bit)?
├─ NO → Deny (Unauthorized)
└─ YES → Allow
The BeTTY Project
https://betty.land
Email: betty-protocol@betty.land
Copyright (C) The BeTTY Project (2025). All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works.
This document itself may not be modified in any way, such as by removing the copyright notice or references to the BeTTY Project, except as needed for the purpose of developing BeTTY standards in which case the procedures for copyrights defined in the BeTTY Process must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by the BeTTY Project or its successors or assigns.
This document and the information contained herein is provided on an "AS IS" basis and THE BETTY PROJECT DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
End of RFC