---
# System prepended metadata

title: Encryption using the Signal Protocol
tags: [Kizuna-architecture]

---

# Encryption using the Signal Protocol
<style> .ui-infobar, #doc.markdown-body { max-width: 2000px; } </style>
###### tags: `Kizuna-architecture`


## Summary of Meeting Notes
* Encryption should be done both in sync and async so that holoport owners don't get to see messages
* Goal should be not sending plaintext messsages between client and holoport
* Key storage
    * DHT: more resilient, less secure
    * Source Chain: less resilient, more secure
    * resiliencey means being able to handle operations when holoports are offline
* Key request (from DHT)
    * problem of key draining
    * problem of simultaneous key pulls
        * clearly a problem even with randomization
    * would be fixed if we ask agents for keys (sync)
        * deliver key via call_remote
* Cryptographic calculations are not safe in wasm
    * holoport owners may get access to private keys
        * implement as close to the APIs
* Relevant resources
    * maybe libsodium api can offer more than hdk (e.g. lair function that does DHE in the background)
    * https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption
    * https://github.com/holochain/holochain/blob/develop/crates/hdk3/src/x_salsa20_poly1305/x_25519_x_salsa20_poly1305_encrypt.rs
    
#### 2/09/2021 Questions and Comments
- Plain text should never be sent from client to HoloPort
- We dont want to store private keys in source chain - not compliant w/ CAL, also a bit risky
  - There has to be at least 1 key stored persistently in client that can decrypt all encrypted entries in source chain. (And this is not the private counterpart of AgentPubKey because that is for signing)
    - If every private entry is encrypted with this key, then this key is weakest point of the encryption scheme we will have.
      - If we will store this in one local device of the agent, how do we ensure that multi-session is possible?
      - OR, we could derive a private/public key from AgentPrivateKey which means that you don't have to store that key persistently because as long as you have the right seed, you will always generate the same private key.
        - Art has said that Chaperone needs to also derive some sort of encryption key so that it can be used for encrypting entries for an agent in the wormhole (what is wormhole?? does this mean the private key leaves local device?)
    - **We may need some form of persistent private key storage in the client when using Holo**
- How do we reconcile the difference between crypto implementation for native Holochain user and Holo hosted user?
  - Holochain has Lair, but Holo does not. So, I think we have to match the native holochain user with Holo use case?
- Where should we generate dynamic keys that can work both for Holo and Holochain
  - Lair
    - Will not work with Holo (since lair is replaced by Chaperone in Holo)
  - Client (on our own)
    - The burden of implementing key infrastructure will be upon us
    - Each project will have different implementation (may introduce lots of security vulnerabilities)
    - We can do basically anything we want to if we do this.
  - Chaperone
    - No idea how this will work yet. Maybe chaperone will expose APIs that we can use and get the private key exposed outside of the iframe?
    - Will chaperone have key generation APIs and will we be able to access those dynamically generated keys so that we can persitently store them?
    - Do we have access to secrets on the browser or will it be completely contained in chaperone? 
      - A no to this answer would mean that we have to introduce something like tweetnacl into Kizuna. 

### External libraries
- https://github.com/signalapp/libsignal-protocol-javascript
- https://www.npmjs.com/package/tweetnacl


## Entry Relationship Diagram
```mermaid
graph LR
    subgraph encryption zome
        subgraph agents
            alice
        end

        subgraph public keys in DHT and source chain
            X3DHKeys
            onetime_key_1
            onetime_key_2
            onetime_key_...
            
            alice-->X3DHKeys
            alice-->onetime_key_1
            alice-->onetime_key_2
            alice-->onetime_key_...    
        end
        
        subgraph private keys in LAIR
            X3DHKeys_pr
            onetime_key_1_pr
            onetime_key_2_pr
            onetime_key_..._pr
            
            X3DHKeys.->|can fetch|X3DHKeys_pr
            onetime_key_1.->|can fetch|onetime_key_1_pr
            onetime_key_2.->|can fetch|onetime_key_2_pr
            onetime_key_... .->|can fetch|onetime_key_..._pr
        end
        
        
        
  end
```
## P2P Encryption using the x_salsa20_poly1305
```mermaid
sequenceDiagram

participant ACD as Alice_Conversation_CELL
participant DHT as DHT
participant BCD as Bobby_Conversation_CELL

ACD-->>ACD: create an x25519 Identity Keypair using 

```
## Functions (using x_salsa_poly_1305)
### `init`
```rust=
fn 
```


## Functions

### `encrypt_message`
- Alice sends a message to offline Bobby

```rust=
fn encrypt_message(message: MessageParameter) -> ExternResult<EncryptedMessage>

pub struct AssociatedData {
    sender_identity_key: X25519PubKey,
    receiver_identity_key: X25519PubKey,
    sender_ephemeral_key: X25519PubKey,
    receiver_onetime_key: X25519PubKey
}

#[hdk_entry(id = "encryptedmessage", visibility = "public")]
pub struct EncryptedMessage {
    id: Option<String>,
    encrypted_data: Vec<Bytes>,
    associated_data: AssociatedData
}
```

```mermaid
sequenceDiagram

participant ACD as Alice_Conversation_CELL
participant BCD as Bobby_Conversation_CELL
participant DHT as DHT

par init
    rect rgba(0,0,255,.1)
        ACD-->>ACD: call publish_prekeys
    end
and
    rect rgba(0,0,255,.1)
        BCD-->>BCD: call publish_prekeys
    end
end

rect rgba(255, 0, 0, .5)
    ACD-->>ACD: call `get_prekey_bundle`
end
ACD-->>ACD: call `agree_on_secret` -> shared_master
Note over ACD: use shared secret to derive two symmetric keys : root key and sending chain key
# ratchet step
ACD-->>ACD: call `create_x25519_keypair` for initial ratchet keypair
ACD-->>ACD: run ratchet_chain <br> (generated_public_key,  bob_onetime_key) -> ratchet_key
ACD-->>ACD: run root_chain (shared_master, ratchet_key) -> (root_key, sending_key)
ACD-->>ACD: run sending_chain <br> (sending_key) -> (chain_key, message_key)
ACD-->>ACD: encrypt 
```

### `publish_prekeys`

```rust=
fn publish_prekeys() -> ExternResult<bool>
```

```rust=

// two entry types = two validation rules
// downside: getting two entries every time a session is being established 
    
// what data type for keys is native to rsm/rust
#[hdk_entry(id = "x3dhkeys", visibility = "public")]
pub struct X3DHKeys = {
    identity_key: X25519PubKey, // once
    signed_prekey: X25519PubKey, // replaced weekly/monthly together with prekey sig
    prekey_signature: X25519PubKey, // replaced weekly/monthly together with prekey
}

#[hdk_entry(id = "x3dhonetimekeys", visibility = "public")]
pub struct X3DHOnetimeKeys = {
    onetime_prekeys: Vec<X25519PubKey> // replaced once available keys are depleted/low
}
```

```rust=
// `hdk3::x_salsa20_poly1305::create_x25519_keypair::create_x25519_keypair`
pub fn create_x25519_keypair() -> HdkResult<X25519PubKey>

// `hdk3::host_fn::sign::sign`
fn sign(key: AgentPubKey, data: SerializedBytes) -> HdkResult<Signature>

// `hdk3::prelude::prelude::signature::Signature`
pub struct Signature(pub Vec<u8>);
```

```mermaid
sequenceDiagram

participant BCD as Bobby_Conversation_CELL
participant DHT as DHT

BCD-->>BCD: call `create_x25519_keypair` for identity key
Note over BCD: can we use the AgentPubKey for the identity key?
BCD-->>BCD: call `create_x25519_keypair` for prekey
BCD-->>BCD: sign prekey
BCD-->>BCD: create X3DHKeys entry
BCD-->>DHT: commit X3DHKeys entry in DHT
DHT-->>BCD: return header address
BCD-->>DHT: link Agent to entry with tag 'x3dhkeys'

loop until required number of onetime keys is met
    BCD-->>BCD: call`create_x25519_keypair`to generate onetime keys
end
BCD-->>BCD: create X3DHOnetimeKeys entry
BCD-->>DHT: commit X3DHOnetimeKeys entry in DHT
DHT-->>BCD: return header address
BCD-->>DHT: link Agent to entry with tag 'x3dhonetimekeys'
```

### `replace_prekey`
```rust=
fn replace_prekey() -> ExternResult<bool>
```

```mermaid
sequenceDiagram

participant BCD as Bobby_Conversation_CELL
participant DHT as DHT

BCD-->>BCD: construct hash address of X3DHKeys entry in DHT
BCD-->>DHT: get X3DHKeys entry from DHT
DHT-->>BCD: return X3DHKeys entry
BCD-->>BCD: call`create_x25519_keypair`to generate prekey
BCD-->>DHT: update X3DHKeys entry in DHT with newly generated prekey
```

### `replenish_onetime_keys`
```rust=
fn replenish_onetime_keys() -> ExternResult<bool>
```
```mermaid
sequenceDiagram

participant BCD as Bobby_Conversation_CELL
participant DHT as DHT

BCD-->>BCD: construct hash address of X3DHOnetimeKeys entry in DHT
BCD-->>DHT: get X3DHOnetimeKeys entry from DHT
DHT-->>BCD: return X3DHOnetimeKeys entry

loop until required number of onetime keys is met
    BCD-->>BCD: call`create_x25519_keypair`to generate onetime keys
end

BCD-->>DHT: update X3DHOnetimeKeys entry in DHT with newly generated keys
```

### `get_prekey_bundle`

```rust=
pub struct PrekeyBundle {
    X3DHKeys: X3DHKeys,
    OnetimeKey: String
}

fn get_prekey_bundle() -> ExternResult<PrekeyBundle>
```
```mermaid
sequenceDiagram

participant ACD as Alice_Conversation_CELL
participant BCD as Bobby_Conversation_CELL
participant DHT as DHT

ACD-->>DHT: get_links from receiver Agent with tag 'x3dhkeys'
DHT-->>ACD: return links
ACD-->>DHT: get link target
DHT-->>ACD: return X3DHKeys entry

ACD-->>DHT: get_links from receiver Agent with tag 'x3dhonetimekeys'
DHT-->>ACD: return links
ACD-->>DHT: get link target
DHT-->>ACD: return X3DHOnetimeKeys entry

ACD-->>ACD: select a onetime prekey at random
Note over ACD: what selection mechanism would be good?
ACD-->>DHT: update_entry to remove selected onetime prekey
Note over DHT: exposes social graph
ACD-->>ACD: return PrekeyBundle
```
### `agree_on_secret`
```mermaid
sequenceDiagram

participant ACD as Alice_Conversation_CELL
participant DHT as DHT

ACD-->>ACD: verify prekey_signature[bobby]
opt verification failed
    ACD-->>ACD: return error
end
ACD-->>ACD: DH(identity_key[alice], signed_prekey[bobby]) -> DH1
ACD-->>ACD: call`create_x25519_keypair`to generate an ephemeral key
ACD-->>ACD: DH(ephemeral_key[alice], identity_key[bobby]) -> DH2
ACD-->>ACD: DH(ephemeral_key[alice], signed_prekey[bobby]) -> DH3
ACD-->>ACD: DH(ephemeral_key[alice], onetime_key[bobby]) -> DH4
ACD-->>ACD: concatenate all DH outputs (DH1||DH2||DH3||DH4) -> shared key
ACD-->>ACD: encode both identity keys as byte strings
ACD-->>ACD: contatenate encoded byte strings -> AD
ACD-->>ACD: return shared key
```


### `ratchet_chain`
```rust=
pub struct RatchetInput {
    public_key_receiver: String //from receiver
    public_key_sender: String //own, used to retrieve private key from lair
}

fn ratchet(input: RatchetInput) -> ExternResult<Key> {
    // Diffie-Hellman
}
```

### `root_chain`
```rust=
pub struct RootInput {
    private_key_shared: String
    dh_output: String
}

pub struct RootPair {
    chain_key: String,
    root_key: String
}

fn ratchet(input: RootInput) -> ExternResult<RootPair> {
    // KDF
}
```

### `sending_chain`
```rust=
pub struct SendingPair{
    chain_key: String,
    message_key: String
}

fn sending_chain(chain_key: Key) -> ExternResult<SendingPair> {
    // KDF
}
```

### `receiving_chain`

### `AEAD`


### `KDF`


### `Encryption`
```mermaid
sequenceDiagram

participant SecMem as Client_Secure_Memory
participant Client as Alice_Client
participant Chap as Alice_Chaperone
participant ACC as Alice_Conversation_Cell
participant DHT as DHT

rect rgba(255, 0, 0, 0.3)
    Note over Client: Key Generation
    Note over SecMem: implement storage to secure memory
    Note over Chap: Will the chaperone have any role in key generation and storage?
    Client-->>Client: generate registrationID <br> (libsignal)
    Client-->>SecMem: store registrationID
    Client-->>Client: generate identityKeyPair <br> (libsignal)
    Client-->>SecMem: store identityKeyPair
    Client-->>Client: generate prekey and signed prekey <br> (libsignal)
    Client-->>DHT: register prekeys and signed prekey
    Note over Client: implement a Store for storing and fetching keys
end

rect rgba(0, 255, 0, 0.2)
    Note over Client: Session Building
    Client-->>Client: Build a session <br> (libsignal)
    Client-->>DHT: fetch prekey bundle
    DHT-->>Client: return prekey bundle
    Client-->>Client: process prekeys <br> (libsignal)
end

rect rgba(0, 0, 255, 0.2)
    Note over Client: encrypt a message
    Client-->>Client: encrypt message payload using Session <br> (libsignal)
    Client-->>ACC: send_message containing the ciphertext as payload
    Note over Client: we can't encrypt other data that the backend needs to process (e.g. receiver) -> attack vector during transmission to backend?
    ACC-->>Client: return message bundle 
end


rect rgba(255, 0, 255, 0.2)
    Note over Client: Decryption
    DHT-->>Client: receive message via signal or getters
    Client-->>Client: find or build matching session with sender
    Client-->>Client: decrypt message payload <br> (libsignal)
end

```