diff --git a/apps/vericrypt/package.json b/apps/vericrypt/package.json
index e83abf0d6..1bc6c6d83 100644
--- a/apps/vericrypt/package.json
+++ b/apps/vericrypt/package.json
@@ -1,6 +1,6 @@
{
"name": "@notesnook/vericrypt",
- "version": "1.3.0",
+ "version": "1.4.0",
"private": true,
"devDependencies": {
"@types/platform": "^1.3.6",
@@ -43,4 +43,4 @@
"last 1 safari version"
]
}
-}
+}
\ No newline at end of file
diff --git a/apps/vericrypt/src/app.tsx b/apps/vericrypt/src/app.tsx
index 12386fcff..2ff91e4c9 100644
--- a/apps/vericrypt/src/app.tsx
+++ b/apps/vericrypt/src/app.tsx
@@ -31,7 +31,7 @@ import { PasteEncryptedData, SyncRequestBody } from "./components/step-4";
import { StepSeperator } from "./components/step-seperator";
import { Footer } from "./components/footer";
import { useState } from "react";
-import { NNCrypto } from "@notesnook/crypto";
+import { NNCrypto, Cipher } from "@notesnook/crypto";
import { Code } from "./components/code";
import { Accordion } from "./components/accordion";
import { DecryptedResult } from "./components/decrypted-result";
@@ -41,7 +41,7 @@ const instructions = [
"Go to Notesnook",
"Open Settings",
<>
- Click on
+ Click on
>,
"Enter your account password for verification",
"Confirm that your generated encryption key matches"
@@ -52,6 +52,7 @@ function App() {
const [salt, setSalt] = useState();
const [key, setKey] = useState();
const [data, setData] = useState();
+ const [accountDataKey, setAccountDataKey] = useState | null | undefined>();
const theme = useTheme({ accent: getDefaultAccentColor(), theme: "light" });
return (
@@ -67,7 +68,7 @@ function App() {
>
-
+
{salt && (
<>
@@ -91,7 +92,7 @@ function App() {
return true;
}}
popup={{
- title: "Your data encryption key",
+ title: "Your master encryption key",
body: key ? (
<>
{
setSalt(undefined);
setPassword(undefined);
setKey(undefined);
setData(undefined);
+ setAccountDataKey(undefined);
}}
/>
>
diff --git a/apps/vericrypt/src/assets/screenshots/devtools_copy_users.png b/apps/vericrypt/src/assets/screenshots/devtools_copy_users.png
new file mode 100644
index 000000000..c861f20c9
Binary files /dev/null and b/apps/vericrypt/src/assets/screenshots/devtools_copy_users.png differ
diff --git a/apps/vericrypt/src/assets/screenshots/firefox/firefox_copy_users.png b/apps/vericrypt/src/assets/screenshots/firefox/firefox_copy_users.png
new file mode 100644
index 000000000..0a85d03c1
Binary files /dev/null and b/apps/vericrypt/src/assets/screenshots/firefox/firefox_copy_users.png differ
diff --git a/apps/vericrypt/src/components/decrypted-result.tsx b/apps/vericrypt/src/components/decrypted-result.tsx
index 79723200a..e605937da 100644
--- a/apps/vericrypt/src/components/decrypted-result.tsx
+++ b/apps/vericrypt/src/components/decrypted-result.tsx
@@ -19,7 +19,7 @@ along with this program. If not, see .
import { Flex, Button, Text, Link } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import { SyncRequestBody } from "./step-4";
-import { NNCrypto } from "@notesnook/crypto";
+import { NNCrypto, Cipher } from "@notesnook/crypto";
import { useEffect, useState } from "react";
import { FcDataEncryption } from "react-icons/fc";
import { Code } from "./code";
@@ -32,6 +32,7 @@ type DecryptedResultProps = {
password: string;
salt: string;
data: SyncRequestBody;
+ accountKey: Cipher<"base64"> | null | undefined;
onRestartProcess: () => void;
};
@@ -51,10 +52,19 @@ export function DecryptedResult(props: DecryptedResultProps) {
};
const crypto = new NNCrypto();
const key = await crypto.exportKey(props.password, props.salt);
+ let encryptionKey = undefined;
+ if (props.accountKey != null){
+ // Need to decrypt the account key
+ props.accountKey.format = "base64"; // account keys don't have the format set, but they're base64.
+ const dataEncryptionKey = JSON.parse(await crypto.decrypt(key, props.accountKey, "text"))
+ encryptionKey = dataEncryptionKey;
+ } else {
+ encryptionKey = key;
+ }
for (const arrayKey in data) {
const array = data[arrayKey];
for (const encryptedItem of (props.data as any)[arrayKey]) {
- const data = await crypto.decrypt(key, encryptedItem, "text");
+ const data = await crypto.decrypt(encryptionKey, encryptedItem, "text");
array.push(JSON.parse(data));
}
}
@@ -150,19 +160,9 @@ export function DecryptedResult(props: DecryptedResultProps) {
support@streetwriters.co
{" "}
or{" "}
- joining our Discord community.
+ join our Discord community.
We'll do our best to alleviate all your worries.
-
- What about open sourcing Notesnook?
-
-
- Open sourcing is another part of garnering our users' trust. We
- have plans to begin
- open sourcing in May but open sourcing will not make this tool
- obsolete. Verifying the integrity of encrypted data at any point in
- time is very important even if the software is open source.
-
);
diff --git a/apps/vericrypt/src/components/step-2.tsx b/apps/vericrypt/src/components/step-2.tsx
index 222acad4f..88eee37d4 100644
--- a/apps/vericrypt/src/components/step-2.tsx
+++ b/apps/vericrypt/src/components/step-2.tsx
@@ -16,11 +16,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import { Flex, Text, Image, Input } from "@theme-ui/components";
+import { Flex, Text, Image, Textarea } from "@theme-ui/components";
import { StepContainer } from "./step-container";
-import DevtoolsCopySaltChrome from "../assets/screenshots/devtools_copy_salt.png";
+import DevtoolsCopyUsersChrome from "../assets/screenshots/devtools_copy_users.png";
-import DevtoolsCopySaltFirefox from "../assets/screenshots/firefox/firefox_copy_salt.png";
+import DevtoolsCopyUsersFirefox from "../assets/screenshots/firefox/firefox_copy_users.png";
import { Accordion } from "./accordion";
import { getCombo } from "../utils/keycombos";
@@ -29,9 +29,11 @@ import { KeyCombo } from "./key-combo";
import { Code } from "./code";
import { useState } from "react";
import { getSourceUrl } from "../utils/links";
+import { Cipher } from "@notesnook/crypto";
type GetAccountSaltProps = {
onSaltSubmitted: (salt: string) => void;
+ setAccountDataKey: (accountDataKey: Cipher<"base64"> | null) => void;
};
const steps = {
@@ -52,10 +54,10 @@ const steps = {
,
Follow the steps as shown in the image:
-
+ ,
- Copy the salt and paste it below.
+ Copy everything in the response and paste it below.
],
firefox: [
@@ -75,10 +77,10 @@ const steps = {
,
Follow the steps as shown in the image:
-
+ ,
- Copy the salt and paste it below.
+ Copy everything in the response and paste it below.
]
};
@@ -114,14 +116,14 @@ export function GetAccountSalt(props: GetAccountSaltProps) {
sx={{ flexDirection: "column" }}
>
- Account salt
+ Account Key Data
- We'll be extracting your account's salt right from
+ You'll be extracting your account's keys right from
Notesnook's local database that lives in your web browser. So put
- on your seat belt and let's get some salt!
+ on your seat belt and let's retrieve those keys.
{instructions?.map((item, index) => (
@@ -141,12 +143,11 @@ export function GetAccountSalt(props: GetAccountSaltProps) {
))}
- {
setIsSaltValid(undefined);
+ /*
+ If there is no dataEncryptionKey, try reading the legacyDataEncryptionKey.
+ If there is a legacyDataEncryptionKey, use this one.
+ If there is no legacyDataEncryptionKey, it is a legacy account (pre DEK update) that has not
+ changed passwords. (Use master key instead.)
+ */
try {
- const value = e.target.value;
- const isValid = Buffer.from(value, "base64").length === 16;
+ const value = JSON.parse(e.target.value);
+ props.setAccountDataKey(value.dataEncryptionKey ?? value.legacyDataEncryptionKey ?? null);
+ const salt = value.salt;
+ const isValid = Buffer.from(salt, "base64").length === 16;
if (!isValid) setIsSaltValid(false);
else {
setIsSaltValid(true);
- props.onSaltSubmitted(value);
+ props.onSaltSubmitted(salt);
}
} catch (e) {
console.error(e);
diff --git a/docs/help/contents/how-is-my-data-encrypted.md b/docs/help/contents/how-is-my-data-encrypted.md
index caff909cd..39bdd13f5 100644
--- a/docs/help/contents/how-is-my-data-encrypted.md
+++ b/docs/help/contents/how-is-my-data-encrypted.md
@@ -41,13 +41,7 @@ This process is repeated every time you sign in.
### 2. Key generation
-After you are signed in, the app requests your user data which includes, among other things, your salt.
-
-> info Salt generation
->
-> When you create an account, the server generates a cryptographically secure random salt for you. This salt is used for key generation.
-
-You password & salt is then used to derive a strong irreversible key using Argon2 as the password key derivation function (PKDF).
+When you first sign up for an account, your client generates two encryption keys. One is a unique data encryption key that encrypts all your notes and other data. The second is your master encryption key, this is derived by your password and predictable salt. This key protects all your encryption keys, like the aforementioned data encryption key. If you change your password, your client will re-encrypt your existing data encryption key with your new master key.
### 3. Encryption key storage
@@ -55,7 +49,7 @@ You password & salt is then used to derive a strong irreversible key using Argon
Instead of storing the key as plain text (and allowing anyone to copy/move it), we use browser's `IndexedDB` to store the key as a `CryptoKey`.
-`CryptoKey` is stored securely by the browser and cannot be exported, viewed, copied except by the app & browser.
+`CryptoKey` is stored securely by the browser and cannot be exported, viewed, or copied except by the app & browser.
# [Mobile](#/tab/mobile)
@@ -70,7 +64,7 @@ Encryption only takes place when you sync. Each item in the database is encrypte
#### How it works
1. The item is read from the database as JSON object and stringified (i.e. converted to a string).
-2. The string is encrypted using the encryption key generated earlier.
+2. The string is encrypted using the data encryption key generated earlier.
3. The result is a JSON object which contains:
1. A base64 encoded `cipher`
2. A 192-bit nonce (`iv`)
@@ -83,3 +77,9 @@ Encryption only takes place when you sync. Each item in the database is encrypte
> See the whole process in action [here.](https://vericrypt.notesnook.com/)
This object is then sent to the server for storage. The server performs no further operation on this data (because it can't).
+
+## Faqs
+
+### I am an old user of Notesnook, I don't have a data encryption key.
+
+Your data encryption key will be created when you change your password.