diff --git a/book.toml b/book.toml index c61e649..1d4ba88 100644 --- a/book.toml +++ b/book.toml @@ -7,4 +7,4 @@ title = "Cwtch Secure Development Handbook" [output.html] mathjax-support = true -default-theme = "navy" +default-theme = "ayu" diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0b40ec3..ccb56b9 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,8 +1,8 @@ # Summary -- [Problem Overview](./overview.md) +- [Overview and History](./overview.md) - [Risk Model](./risk.md) -- [Cwtch Overview](./cwtch-overview.md) +- [Cwtch Technical Basics](./cwtch-overview.md) - [Open Questions](./open-questions.md) - [Cwtch Library](./cwtch.md) - [Message Formats](./message_formats.md) diff --git a/src/android.md b/src/android.md index 2f4e193..f3d7247 100644 --- a/src/android.md +++ b/src/android.md @@ -1,3 +1,28 @@ # Android Service -(Currently under active development, will be documented here once it has been merged into trunk) \ No newline at end of file +[Adapted from: Discreet Log #11: Integrating FFI processes with Android services](https://openprivacy.ca/discreet-log/11-android-ffi-service-integration/) + +In addition to needing to make plain ol’ method calls into the Cwtch library, we also need to be able to communicate with (and receive events from) long-running Cwtch goroutines that keep the Tor process running in the background, manage connection and conversation state for all your contacts, and handle a few other monitoring and upkeep tasks as well. This isn’t really a problem on traditionally multitasking desktop operating systems, but on mobile devices running Android we have to contend with shorter sessions, frequent unloads, and network and power restrictions that can vary over time. As Cwtch is intended to be metadata resistant and privacy-centric, we also want to provide notifications without using the Google push notification service. + +The solution for long-running network apps like Cwtch is to put our FFI code into an Android Foreground Service. (And no, it’s not lost on me that the code for our backend is placed in something called a ForegroundService.) With a big of finagling, the WorkManager API allows us to create and manage various types of services including ForegroundServices. This turned out to be a great choice for us, as our gomobile FFI handler happened to already be written in Kotlin, and WorkManager allows us to specify a Kotlin coroutine to be invoked as the service. + +If you’d like to follow along, our WorkManager specifications are created in the handleCwtch() method of [MainActivity.kt](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt), and the workers themselves are defined in [FlwtchWorker.kt](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt). + +Our plain ol’ method calls to FFI routines are also upgraded to be made as WorkManager work requests, which allows us to conveniently pass the return values back via the result callback. + +One initial call (aptly named Start) gets hijacked by FlwtchWorker to become our eventbus loop. Since FlwtchWorker is a coroutine, it’s easy for it to yield and resume as necessary while waiting for events to be generated. Cwtch’s goroutines can then emit events, which will be picked up by FlwtchWorker and dispatched appropriately. + +FlwtchWorker’s eventbus loop is not just a boring forwarder. It needs to check for certain message types that affect the Android state; for example, new message events should typically display notifications that the user can click to go to the appropriate conversation window, even when the app isn’t running in the foreground. When the time does come to forward the event to the app, we use LocalBroadcastManager to get the notification to MainActivity.onIntent. From there, we in turn use Flutter MethodChannels to forward the event data from Kotlin into the frontend’s Flutter engine, where the event finally gets parsed by Dart code that updates the UI as necessary. + +Messages and other permanent state are stored on disk by the service, so the frontend doesn’t need to be updated if the app isnt open. However, some things (like dates and unread messages) can then lead to desyncs between the front and back ends, so we check for this at app launch/resume to see if we need to reinitialize Cwtch and/or resync the UI state. + +Finally, while implementing these services on Android we observed that WorkManager is very good at persisting old enqueued work, to the point that old workers were even being resumed after app reinstalls! Adding calls to pruneWork() helps mitigate this, as long as the app was shut down gracefully and old jobs were properly canceled. This frequently isn’t the case on Android, however, so as an additional mitigation we found it useful to tag the work with the native library directory name: + + private fun getNativeLibDir(): String { + val ainfo = this.applicationContext.packageManager.getApplicationInfo( + "im.cwtch.flwtch", // Must be app name + PackageManager.GET_SHARED_LIBRARY_FILES) + return ainfo.nativeLibraryDir + } + +…then, whenever the app is launched, we cancel any jobs that aren’t tagged with the correct current library directory. Since this directory name changes between app installs, this technique prevents us from accidentally resuming with an outdated service worker. \ No newline at end of file diff --git a/src/cwtch-overview.md b/src/cwtch-overview.md index 52f312f..ccf13e0 100644 --- a/src/cwtch-overview.md +++ b/src/cwtch-overview.md @@ -1,7 +1,6 @@ -# Cwtch Overview - -This page presents a brief technical overview of the Cwtch system. +# Cwtch Technical Basics +This page presents a brief technical overview of the Cwtch protocol. ## A Cwtch Profile @@ -9,8 +8,7 @@ Users can create one of more Cwtch Profiles. Each profile generates a random ed2 Tor. In addition to the cryptographic material, a profile also contains a list of Contacts (other Cwtch profile public keys + -associated data about that profile like nickname and (optionally) historical messages), a list of Groups (containing the group cryptographic material in -addition to other associated data like the group nickname and historical messages). +associated data about that profile like nickname and (optionally) historical messages), a list of Groups (containing the group cryptographic material in addition to other associated data like the group nickname and historical messages). ## 2-party conversions: Peer to Peer @@ -31,14 +29,32 @@ fact - it is impossible to definitely prove that the exchange happened at all. After, the authentication protocol the two parties may exchange messages with each other freely. -## Multi-party conversations: Peer to Server +## Multi-party conversations: Groups and Peer to Server Communication **Note: Metadata Resistant Group Communication is still an active research area and what is documented here will likely change in the future.** +When a person wants to start a group conversation they first randomly generate a secret `Group Key`. All group communication will be encrypted using this key. + +Along with the `Group Key`, the group creator also decides on a **Cwtch Server** to use as the host of the group. +For more information on how Servers authenticate themselves see [key bundles](./key_bundles.md). + +A `Group Identifier` is generated using the group key and the group server and these three elements are packaged up +into an invite that can be sent to potential group members (e.g. over existing peer-to-peer connections). + +To send a message to the group, a profile connects to the server hosting the group (see below), and encrypts +their message using the `Group Key` and generates a cryptographic signature over the `Group Id`, `Group Server` +and the decrypted message (see: [wire formats](./message_formats.md) for more information). + +To receive message from the group, a profile connected to the server hosting the group and downloads *all* messages (since +their previous connection). Profiles then attempt to decrypt each message using the `Group Key` and if successful attempt +to verify the signature (see [Cwtch Servers](./server.md) [Cwtch Groups](./groups.md) for an overview of attacks and mitigations). + +### Servers are Peers + In many respects communication with a server is identical to communication with a regular Cwtch peer, all the same steps above are taken however the server always acts as the inbound peer, and the outbound -peer always uses newly generated keypair as their "longterm identity". +peer always uses newly generated **ephemeral keypair** as their "longterm identity". As such peer-server conversations only differ in the *kinds* of messages that are sent between the two parties, with the server relaying all messages that it receives and also allowing any client to query for older messages. diff --git a/src/overview.md b/src/overview.md index 62abe58..1baa944 100644 --- a/src/overview.md +++ b/src/overview.md @@ -9,6 +9,20 @@ processes. ![](https://docs.openprivacy.ca/cwtch-security-handbook/2.png) +## What is Cwtch? + +Cwtch (/kʊtʃ/ - a Welsh word roughly translating to “a hug that creates a safe place”) is a decentralized, privacy-preserving, multi-party messaging protocol that can be used to build metadata resistant applications. + +* **Decentralized and Open**: There is no “Cwtch service” or “Cwtch network”. Participants in Cwtch can host their own safe spaces, or lend their infrastructure to others seeking a safe space. The Cwtch protocol is open, and anyone is free to build bots, services and user interfaces and integrate and interact with Cwtch. +* **Privacy Preserving**: All communication in Cwtch is end-to-end encrypted and takes place over Tor v3 onion services. +* **Metadata Resistant**: Cwtch has been designed such that no information is exchanged or available to anyone without their explicit consent, including on-the-wire messages and protocol metadata. + +### A Video Explainer + + + ## A (Brief) History of Metadata Resistant Chat In recent years, public awareness of the need and benefits of end-to-end