From d659d975cd4061ee9dac2061167cca2afdcd2c4f Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 5 Jan 2018 18:40:57 +0100 Subject: [PATCH] All: Documentation and minor tweaks for E2EE --- CliClient/app/autocompletion.js | 6 +- CliClient/app/command-e2ee.js | 8 +- CliClient/run.sh | 2 +- .../app/gui/EncryptionConfigScreen.jsx | 13 + README_e2ee.md | 26 ++ .../components/screens/encryption-config.js | 9 + Tools/build-website.js | 4 + docs/help/e2ee.html | 245 ++++++++++++++ docs/help/spec.html | 314 ++++++++++++++++++ 9 files changed, 622 insertions(+), 5 deletions(-) create mode 100644 README_e2ee.md create mode 100644 docs/help/e2ee.html create mode 100644 docs/help/spec.html diff --git a/CliClient/app/autocompletion.js b/CliClient/app/autocompletion.js index db40cc48f..cca40e206 100644 --- a/CliClient/app/autocompletion.js +++ b/CliClient/app/autocompletion.js @@ -1,7 +1,7 @@ var { app } = require('./app.js'); -var { Note } = require('lib/models/note.js'); -var { Folder } = require('lib/models/folder.js'); -var { Tag } = require('lib/models/tag.js'); +var Note = require('lib/models/Note.js'); +var Folder = require('lib/models/Folder.js'); +var Tag = require('lib/models/Tag.js'); var { cliUtils } = require('./cli-utils.js'); var yargParser = require('yargs-parser'); diff --git a/CliClient/app/command-e2ee.js b/CliClient/app/command-e2ee.js index 2822b6c5f..2bf4c092c 100644 --- a/CliClient/app/command-e2ee.js +++ b/CliClient/app/command-e2ee.js @@ -14,7 +14,7 @@ class Command extends BaseCommand { } description() { - return _('Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt` and `target-status`.'); + return _('Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status` and `target-status`.'); } options() { @@ -75,6 +75,11 @@ class Command extends BaseCommand { return; } + if (args.command === 'status') { + this.stdout(_('Encryption is: %s', Setting.value('encryption.enabled') ? _('Enabled') : _('Disabled'))); + return; + } + if (args.command === 'target-status') { const fs = require('fs-extra'); const pathUtils = require('lib/path-utils.js'); @@ -169,6 +174,7 @@ class Command extends BaseCommand { } } + return; } } diff --git a/CliClient/run.sh b/CliClient/run.sh index eeb6dc569..43f11e2a3 100755 --- a/CliClient/run.sh +++ b/CliClient/run.sh @@ -4,4 +4,4 @@ CLIENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" bash "$CLIENT_DIR/build.sh" && node "$CLIENT_DIR/build/main.js" --profile ~/Temp/TestNotes2 --stack-trace-enabled --log-level debug --env dev "$@" -#bash $CLIENT_DIR/build.sh && NODE_PATH="$CLIENT_DIR/build/" node build/main.js --profile ~/Temp/TestNotes2 --stack-trace-enabled --log-level debug --env dev "$@" \ No newline at end of file +# bash $CLIENT_DIR/build.sh && NODE_PATH="$CLIENT_DIR/build/" node build/main.js --profile ~/.config/joplin --stack-trace-enabled --log-level debug "$@" \ No newline at end of file diff --git a/ElectronClient/app/gui/EncryptionConfigScreen.jsx b/ElectronClient/app/gui/EncryptionConfigScreen.jsx index d92207174..6512d9c17 100644 --- a/ElectronClient/app/gui/EncryptionConfigScreen.jsx +++ b/ElectronClient/app/gui/EncryptionConfigScreen.jsx @@ -9,6 +9,8 @@ const { _ } = require('lib/locale.js'); const { time } = require('lib/time-utils.js'); const dialogs = require('./dialogs'); const shared = require('lib/components/shared/encryption-config-shared.js'); +const pathUtils = require('lib/path-utils.js'); +const { bridge } = require('electron').remote.require('./bridge'); class EncryptionConfigScreenComponent extends React.Component { @@ -151,6 +153,17 @@ class EncryptionConfigScreenComponent extends React.Component {
+
+

+ Important: This is a beta feature. It has been extensively tested and is already in use by some users, but it is possible that some bugs remain. +

+

+ If you wish to you use it, it is recommended that you keep a backup of your data. The simplest way is to regularly backup {pathUtils.toSystemSlashes(Setting.value('profileDir'), process.platform)} +

+

+ For more information about End-To-End Encryption (E2EE) and how it is going to work, please check the documentation: {bridge().openExternal('http://joplin.cozic.net/help/e2ee.html')}} href="#">http://joplin.cozic.net/help/e2ee.html +

+

{_('Status')}

{_('Encryption is:')} {this.props.encryptionEnabled ? _('Enabled') : _('Disabled')}

{decryptedItemsInfo} diff --git a/README_e2ee.md b/README_e2ee.md new file mode 100644 index 000000000..09676ce2a --- /dev/null +++ b/README_e2ee.md @@ -0,0 +1,26 @@ +# About End-To-End Encryption (E2EE) + +3. Now you need to synchronise all your notes so that thEnd-to-end encryption (E2EE) is a system where only the owner of the notes, notebooks, tags or resources can read them. It prevents potential eavesdroppers - including telecom providers, internet providers, and even the developer of Joplin from being able to access the data. + +The systems is designed to defeat any attempts at surveillance or tampering because no third parties can decipher the data being communicated or stored. + +There is a small overhead to using E2EE since data constantly have to be encrypted and decrypted so consider whether you really need the feature. + +# Enabling E2EE + +Due to the decentralised nature of Joplin, E2EE needs to be manually enabled on all the applications that you synchronise with. It is recommended to first enable it on the desktop or terminal application since they generally run on more powerful devices (unlike the mobile application), and so they can encrypt the initial data faster. + +To enable it, please follow these steps: + +1. On your first device (eg. on the desktop application), go to the Encryption Config screen and click "Enable encryption" +2. Input your password. This is the Master Key password which will be used to encrypt all your notes. Make sure you do not forget it since, for security reason, it cannot be recovered. +ey are sent encrypted to the sync target (eg. to OneDrive, Nextcloud, etc.). Wait for any synchronisation that might be in progress and click on "Synchronise". +4. Wait for this synchronisation operation to complete. Since all the data needs to be re-sent (encrypted) to the sync target, it may take a long time, especially if you have many notes and resources. Note that even if synchronisation seems stuck, most likely it is still running - do not cancel it and simply let it run over night if needed. +5. Once this first synchronisation operation is done, open the next device you are synchronising with. Click "Synchronise" and wait for the sync operation to complete. The device will receive the master key, and you will need to provide the password for it. At this point E2EE will be automatically enabled on this device. Once done, click Synchronise again and wait for it to complete. +6. Repeat step 5 for each device. + +Once all the devices are in sync with E2EE enabled, the encryption/decryption should be mostly transparent. Occasionally you may see encrypted items but they will get decrypted in the background eventually. + +# Disabling E2EE + +Follow the same procedure as above but instead disable E2EE on each device one by one. Again it might be simpler to do it one device at a time and to wait every time for the synchronisation to complete. \ No newline at end of file diff --git a/ReactNativeClient/lib/components/screens/encryption-config.js b/ReactNativeClient/lib/components/screens/encryption-config.js index e66138368..afd9a1108 100644 --- a/ReactNativeClient/lib/components/screens/encryption-config.js +++ b/ReactNativeClient/lib/components/screens/encryption-config.js @@ -152,6 +152,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent { } render() { + const theme = themeStyle(this.props.theme); const masterKeys = this.state.masterKeys; const decryptedItemsInfo = this.props.encryptionEnabled ? {shared.decryptedStatText(this)} : null; @@ -187,6 +188,14 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent { + + + Important: This is a *beta* feature. It has been extensively tested and is already in use by some users, but it is possible that some bugs remain. + If you wish to you use it, it is recommended that you keep a backup of your data. The simplest way is to regularly backup your notes from the desktop or terminal application. + For more information about End-To-End Encryption (E2EE) and how it is going to work, please check the documentation: + { Linking.openURL('http://joplin.cozic.net/help/e2ee.html') }}>http://joplin.cozic.net/help/e2ee.html + + {_('Status')} {_('Encryption is: %s', this.props.encryptionEnabled ? _('Enabled') : _('Disabled'))} {decryptedItemsInfo} diff --git a/Tools/build-website.js b/Tools/build-website.js index a80159e8a..6bd9137d2 100644 --- a/Tools/build-website.js +++ b/Tools/build-website.js @@ -308,6 +308,10 @@ async function main() { renderFileToHtml(rootDir + '/README_desktop.md', rootDir + '/docs/desktop/index.html', { selectedDesktop: 'selected', }); + + renderFileToHtml(rootDir + '/README_e2ee.md', rootDir + '/docs/help/e2ee.html', {}); + renderFileToHtml(rootDir + '/README_spec.md', rootDir + '/docs/help/spec.html', {}); + } main().catch((error) => { diff --git a/docs/help/e2ee.html b/docs/help/e2ee.html new file mode 100644 index 000000000..066ec8f9d --- /dev/null +++ b/docs/help/e2ee.html @@ -0,0 +1,245 @@ + + + + Joplin - an open source note taking and to-do application with synchronisation capabilities + + + + + + + + + + + + +
+ +
+ +

oplin

+

An open source note taking and to-do application with synchronisation capabilities.

+
+ + + +
+

About End-To-End Encryption (E2EE)

+
    +
  1. Now you need to synchronise all your notes so that thEnd-to-end encryption (E2EE) is a system where only the owner of the notes, notebooks, tags or resources can read them. It prevents potential eavesdroppers - including telecom providers, internet providers, and even the developer of Joplin from being able to access the data.
  2. +
+

The systems is designed to defeat any attempts at surveillance or tampering because no third parties can decipher the data being communicated or stored.

+

There is a small overhead to using E2EE since data constantly have to be encrypted and decrypted so consider whether you really need the feature.

+

Enabling E2EE

+

Due to the decentralised nature of Joplin, E2EE needs to be manually enabled on all the applications that you synchronise with. It is recommended to first enable it on the desktop or terminal application since they generally run on more powerful devices (unlike the mobile application), and so they can encrypt the initial data faster.

+

To enable it, please follow these steps:

+
    +
  1. On your first device (eg. on the desktop application), go to the Encryption Config screen and click "Enable encryption"
  2. +
  3. Input your password. This is the Master Key password which will be used to encrypt all your notes. Make sure you do not forget it since, for security reason, it cannot be recovered. +ey are sent encrypted to the sync target (eg. to OneDrive, Nextcloud, etc.). Wait for any synchronisation that might be in progress and click on "Synchronise".
  4. +
  5. Wait for this synchronisation operation to complete. Since all the data needs to be re-sent (encrypted) to the sync target, it may take a long time, especially if you have many notes and resources. Note that even if synchronisation seems stuck, most likely it is still running - do not cancel it and simply let it run over night if needed.
  6. +
  7. Once this first synchronisation operation is done, open the next device you are synchronising with. Click "Synchronise" and wait for the sync operation to complete. The device will receive the master key, and you will need to provide the password for it. At this point E2EE will be automatically enabled on this device. Once done, click Synchronise again and wait for it to complete.
  8. +
  9. Repeat step 5 for each device.
  10. +
+

Once all the devices are in sync with E2EE enabled, the encryption/decryption should be mostly transparent. Occasionally you may see encrypted items but they will get decrypted in the background eventually.

+

Disabling E2EE

+

Follow the same procedure as above but instead disable E2EE on each device one by one. Again it might be simpler to do it one device at a time and to wait every time for the synchronisation to complete.

+ + + + + diff --git a/docs/help/spec.html b/docs/help/spec.html new file mode 100644 index 000000000..ee8fc71df --- /dev/null +++ b/docs/help/spec.html @@ -0,0 +1,314 @@ + + + + Joplin - an open source note taking and to-do application with synchronisation capabilities + + + + + + + + + + + + +
+ +
+ +

oplin

+

An open source note taking and to-do application with synchronisation capabilities.

+
+ + + +
+

Encryption

+

Encrypted data is encoded to ASCII because encryption/decryption functions in React Native can only deal with strings. So for compatibility with all the apps we need to use the lowest common denominator.

+

Encrypted data format

+ + + + + + + + + + + + + + + + + + +
NameSize
Identifier3 chars ("JED")
Version number2 chars (Hexa string)
+

This is followed by the encryption metadata:

+ + + + + + + + + + + + + + + + + + + + + +
NameSize
Length6 chars (Hexa string)
Encryption method2 chars (Hexa string)
Master key ID32 chars (Hexa string)
+

See lib/services/EncryptionService.js for the list of available encryption methods.

+

Data chunk

+

The data is encoded in one or more chuncks for performance reasons. That way it is possible to take a block of data from one file and encrypt it to another block in another file. Encrypting/decrypting the whole file in one go would not work (on mobile especially).

+ + + + + + + + + + + + + + + + + +
NameSize
Length6 chars (Hexa string)
Data("Length" bytes) (ASCII)
+

Master Keys

+

The master keys are used to encrypt and decrypt data. They can be generated from the Encryption Service, and are saved to the database. They are themselves encrypted via a user password.

+

These encrypted master keys are transmitted with the sync data so that they can be available to each client. Each client will need to supply the user password to decrypt each key.

+

The application supports multiple master keys in order to handle cases where one offline client starts encrypting notes, then another offline client starts encrypting notes too, and later both sync. Both master keys will have to be decrypted separately with the user password.

+

Only one master key can be active for encryption purposes. For decryption, the algorithm will check the Master Key ID in the header, then check if it's available to the current app and, if so, use this for decryption.

+

Encryption Service

+

The applications make use of the EncryptionService class to handle encryption and decryption. Before it can be used, a least one master key must be loaded into it and marked as "active".

+

Encryption workflow

+

Items are encrypted only during synchronisation, when they are serialised (via BaseItem.serializeForSync), so before being sent to the sync target.

+

They are decrypted by DecryptionWorker in the background.

+

The apps handle displaying both decrypted and encrypted items, so that user is aware that these items are there even if not yet decrypted. Encrypted items are mostly read-only to the user, except that they can be deleted.

+

Enabling and disabling encryption

+

Enabling/disabling E2EE while two clients are in sync might have an unintuitive behaviour (although that behaviour might be correct), so below some scenarios are explained:

+
    +
  • If client 1 enables E2EE, all items will be synced to target and will appear encrypted on target. Although all items have been re-uploaded to the target, their timestamps did not change (because the item data itself has not changed, only its representation). Because of this, client 2 will not re-download the items - it does not need to do so anyway since it has already the item data.

    +
  • +
  • When a client sync and download a master key for the first time, encryption will be automatically enabled (user will need to supply the master key password). In that case, all items that are not encrypted will be re-synced. Uploading only non-encrypted items is an optimisation since if an item is already encrypted locally it means it's encrypted on target too.

    +
  • +
  • If both clients are in sync with E2EE enabled: if client 1 disable E2EE, it's going to re-upload all the items unencrypted. Client 2 again will not re-download the items for the same reason as above (data did not change, only representation). Note that user must manually disable E2EE on all clients otherwise some will continue to upload encrypted items. Since synchronisation is stateless, clients do not know whether other clients use E2EE or not so this step has to be manual.

    +
  • +
  • Although messy, Joplin supports having some clients send encrypted items and others unencrypted ones. The situation gets resolved once all the clients have the same E2EE settings.

    +
  • +
+ + + + +