File Layer
The platform layer has decrypted (or ”unlocked”) access to SNodes.
The normal lifecycle for secret nodes is for the user to start by decrypting some node, revealing its plaintext contents. If this contains a directory, then it will contain human-readable links and further pointers to more nodes. By following these pointers and decrypting their contents, the users "discovers" or "materializes" the plaintext file DAG.

Unlocking

To read a node, the user needs to have the key either available from another node which they have access to, in the shared_with_me or shared_by_me sections, or stored on their system directly.
To read or ”unlock“ a private node, you need the node and its key:
1
data UnlockPointer = UnlockPointer
2
{ rawKey :: Bytes
3
, index :: SHA3_256 Namefilter
4
, algorithm :: CryptoAlgorithm -- e.g. AES-GCM
5
}
6
7
unlock :: UnlockPointer -> DecryptedNode
Copied!

Unlocked Private Node Schema

1
data DecryptedNode
2
= DecryptedDirectory PrivateDirectory
3
| DecryptedFile PrivateFile
4
-- Links
5
| DecryptedSymlink NameFilter CryptoAlgorithm Bytes
6
| DecryptedMovedTo UnlockPointer
7
8
data DecryptedFile = DecryptedFile
9
{ metadata :: Metadata -- NOTE includes events, &c
10
, bareName :: BareNameFilter
11
, revision :: SpiralRatchet
12
, algorithm :: CryptoAlgorithm
13
, content :: Content
14
}
15
16
data Content
17
= Inline ByteString -- e.g. {inline: 0x123456}
18
| ExternalContent SpiralRatchet Natural -- Number of segments
19
20
data DecryptedDirectory = DecryptedDirectory
21
{ metadata :: Metadata
22
, bareNameFilter :: BareNameFilter
23
, ratchet :: SpiralRatchet
24
, links :: Map Text UnlockPointer
25
}
Copied!

Secure Recursive Read Access

The private section is recursively protected with AES-256 encryption. This is to say that each vnode is encrypted with an AES key, and each of its children are encrypted separately with their own randomly derived AES keys. A node holds the keys to each of its children. In this way, having a key for a node also grants read access to that entire subgraph.

Content Access

Content may be inlined or externalized. Inlined content is decrypted along with the header.
Since external content is separate from the header, it needs a unique namefilter derived from a ratchet (to avoid forcing lookups to go through the header). If the key were derived from the header's key, then the file would be re-encrypted e.g. every time the metadata changed.
External content namefilters are defined thus:
1
const segmentNames = (file) => {
2
const {bareNamefilter, content: {ratchet, count}} = file.header
3
const key = ratchet.toBytes()
4
5
let names = []
6
for (i = 0; i < count; i++) {
7
names[i] = bareNamefilter
8
.append(sha3_256(key))
9
.append(sha3_256(`${key}${i}`))
10
.saturate()
11
}
12
13
return contentNames
14
}
Copied!

Revocation

Read access revocation is achieved by changing the AES key and linking to a higher node. As such, it is not recommended for a user with write permissions to rotate the key of the root of their subgraph, unless they’re able to redistribute that key somehow. For example, the root user is able to update the key for the root of the graph, and distribute that key to their other user instances by the shared_by_me mechanism.
A node with no valid key pointing at it is said to be orphaned, since it has no parents that are capable of accessing the data locked in the node. It may be marked for garbage collection by the root user.

Decrypted Nodes

Since the structure of a cryptDAG is hidden completely from the outside world, there is a very strict separation between the platform layer, and how things are organized at the protocol layer. There are still two layers, but the protocol layer is more closely relied on by the platform layer.
The protocol layer describes encrypted nodes, with a special naming scheme and organized in a HAMT (see Data Layer). These can be converted to a decrypted virtual node via an external symmetric key.

Key Rotation

While the ratchet revision maintains forward-secrecy, backwards-secrecy is achieved with a ratchet reset (which is equivalent to a key rotation). This involves:
  1. 1.
    Placing a MovedTo node containing a pointer to the new namefilter
  2. 2.
    Re-sharing the rotated ratchet with all authorized users
  3. 3.
    Adding the file descriptor to the file descriptor graveyard
See Share for more information on how to share keys with other users.
Last modified 7mo ago