Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desktop: Resolves #8380: Always show reencrypt button #8555

Conversation

personalizedrefrigerator
Copy link
Collaborator

@personalizedrefrigerator personalizedrefrigerator commented Jul 25, 2023

Summary

Shows the re-encryption button under "Encryption" settings always, not just when the encryption.shouldReencrypt setting has value Setting.SHOULD_REENCRYPT_YES.

The re-encryption button is now shown under "Advanced".

Fixes #8380.

To-do

While this pull request could be merged as is, it may be helpful to have the following:

  • Wait for sync to finish before allowing users to press "reencrypt all"
    • I am no longer convinced that this is necessary. Because reencryptAll works by calling BaseItem.forceSyncAll();, then reg.waitForSyncFinishedThenSync();, any unsynchronized items should remain queued to be synchronized.

Testing

  1. Ensure Joplin has several notes/folders.
  2. Ensure Joplin is connected to a sync target and can sync successfully.
  3. Do a full sync.
  4. Close Joplin
  5. Add a new encryption method to EncryptionService.ts
Example Diff
diff --git a/packages/lib/services/e2ee/EncryptionService.ts b/packages/lib/services/e2ee/EncryptionService.ts
index 3e835a753..b4ce6d41d 100644
--- a/packages/lib/services/e2ee/EncryptionService.ts
+++ b/packages/lib/services/e2ee/EncryptionService.ts
@@ -39,6 +39,7 @@ export enum EncryptionMethod {
 	SJCL1a = 5,
 	Custom = 6,
 	SJCL1b = 7,
+	SJCL1c = 8,
 }
 
 export interface EncryptOptions {
@@ -70,7 +71,7 @@ export default class EncryptionService {
 	// changed easily since the chunk size is incorporated into the encrypted data.
 	private chunkSize_ = 5000;
 	private decryptedMasterKeys_: Record<string, DecryptedMasterKey> = {};
-	public defaultEncryptionMethod_ = EncryptionMethod.SJCL1b; // public because used in tests
+	public defaultEncryptionMethod_ = EncryptionMethod.SJCL1c; // public because used in tests
 	private defaultMasterKeyEncryptionMethod_ = EncryptionMethod.SJCL4;
 
 	private headerTemplates_ = {
@@ -332,6 +333,26 @@ export default class EncryptionService {
 				}
 			},
 
+			// Test: DO NOT COMMIT
+			[EncryptionMethod.SJCL1c]: () => {
+				try {
+					// We need to escape the data because SJCL uses encodeURIComponent to process the data and it only
+					// accepts UTF-8 data, or else it throws an error. And the notes might occasionally contain
+					// invalid UTF-8 data. Fixes https://github.com/laurent22/joplin/issues/2591
+					return sjcl.json.encrypt(key, escape(plainText), {
+						v: 1, // version
+						iter: 2000, // Since the master key already uses key derivations and is secure, additional iteration here aren't necessary, which will make decryption faster. SJCL enforces an iter strictly greater than 100
+						ks: 512, // Key size - "256-bit is the golden standard that we should follow."
+						ts: 64, // ???
+						mode: 'ccm', //  The cipher mode is a standard for how to use AES and other algorithms to encrypt and authenticate your message. OCB2 mode is slightly faster and has more features, but CCM mode has wider support because it is not patented.
+						// "adata":"", // Associated Data - not needed?
+						cipher: 'aes',
+					});
+				} catch (error) {
+					throw this.wrapSjclError(error);
+				}
+			},
+
 			// 2020-01-23: Deprecated - see above.
 			// Was used to encrypt master keys
 			[EncryptionMethod.SJCL2]: () => {
@@ -404,7 +425,7 @@ export default class EncryptionService {
 		try {
 			const output = sjcl.json.decrypt(key, cipherText);
 
-			if (method === EncryptionMethod.SJCL1a || method === EncryptionMethod.SJCL1b) {
+			if (method === EncryptionMethod.SJCL1a || method === EncryptionMethod.SJCL1b || method === EncryptionMethod.SJCL1c) {
 				return unescape(output);
 			} else {
 				return output;
@@ -655,7 +676,7 @@ export default class EncryptionService {
 	}
 
 	public isValidEncryptionMethod(method: EncryptionMethod) {
-		return [EncryptionMethod.SJCL, EncryptionMethod.SJCL1a, EncryptionMethod.SJCL1b, EncryptionMethod.SJCL2, EncryptionMethod.SJCL3, EncryptionMethod.SJCL4].indexOf(method) >= 0;
+		return [EncryptionMethod.SJCL, EncryptionMethod.SJCL1a, EncryptionMethod.SJCL1b, EncryptionMethod.SJCL1c, EncryptionMethod.SJCL2, EncryptionMethod.SJCL3, EncryptionMethod.SJCL4].indexOf(method) >= 0;
 	}
 
 	public async itemIsEncrypted(item: any) {
  1. Re-build and re-launch Joplin
  2. Open settings > encryption > advanced
  3. Click "Re-encrypt data"
  4. Wait for sync to finish
  5. Quit Joplin
  6. Reset EncryptionService.ts to what it was before step 4
  7. Open Joplin and click "delete local data and re-downlad from sync target"
  8. Verify that none of the downloaded notes can be decrypted.

@personalizedrefrigerator personalizedrefrigerator marked this pull request as ready for review August 2, 2023 04:21
@laurent22 laurent22 merged commit 8696052 into laurent22:dev Aug 8, 2023
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Show button to reencrypt data
2 participants