Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Derive encryption key in dashboard using Argon2 #424

Merged
merged 17 commits into from
Jul 23, 2023

Conversation

hlxid
Copy link
Member

@hlxid hlxid commented Jan 9, 2022

See #408 (comment).

After doing some research I found out that a key derivation function like PBKDF2 is probably better suited for this than a plain hashing algorithm.
CryptoJS actually already does this when a password is provided to the AES.encrypt function.
We now just do the key derivation ourselves in the dashboard, only transmit the key, and pass the key to CryptoJS.
Because we're now ourselves managing the encryption key we also need to manage the salt and initialization vector.

All old configurations will be automatically migrated on the first login.

Todo list:

  • First implementation
  • Code cleanup and documentation
  • Fix and update tests

Any feedback is highly appreciated.

@hlxid hlxid self-assigned this Jan 9, 2022
@hlxid hlxid marked this pull request as draft January 9, 2022 21:42
@hlxid hlxid marked this pull request as ready for review January 11, 2022 17:20
@hlxid hlxid requested a review from sebinside January 11, 2022 17:21
Copy link
Member

@sebinside sebinside left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I welcome the changes to increase security, I am not qualified enough to state whether this is correctly realized. Thank for testing, I hope migration will work 😁

* @param salt the salt that is used for key derivation.
* @returns a hex encoded string of the derived key.
*/
export function deriveEncryptionKey(password: string, salt: string): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really deriving or more precisely calculating?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... this function is just a wrapper around PBKDF2 (Password-Based Key Derivation Function 2). So I assume this is deriving?

return crypto
.PBKDF2(password, saltWordArray, {
keySize: 256 / 32,
iterations: 5000,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 5000 iterations like normal, or your approach, where does this originate, what does it mean? a comment might be a good fit for these settings

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See b504cc5

@@ -292,12 +381,36 @@ export class PersistenceManager {
if (bundles.length > 0) {
try {
this.nodecg.log.info("Attempting to automatically login...");
const loadResult = await this.load(password);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code duplication with crypto.ts is required because there is no way to serve the same functionality in the extension and the dashboard? Then I would propose to at least add a note to minimize breaking this in evolution (which could probably mess up configs...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f3ee487

@hlxid
Copy link
Member Author

hlxid commented Jul 24, 2022

Because of the problems with this PBKDF2 implementation (see b504cc5) I'm thinking about exploring argon2 for this. It has a WebAssembly implementation available and thus has not the performance problems that running PBKDF2 in JS has. Additionally argon2 seems to be more secure. If we're changing the config layout we might as well do it future-proof. However this is currently only a idea and I will need to explore that possibility and decide whether or not we should do it.

I still should add at least one unit test for migration. It has always worked for my various configs but I don't want to have the migration suddenly break in future nodecg-io versions.

Additionally I should write the security assumptions that nodecg-io makes into the docs before merging this PR.

I hopefully should have some spare time in about three weeks to do all this, handle some maintenance tasks like removing the broken curseforge service and release 0.3.0.

@hlxid hlxid marked this pull request as draft August 9, 2022 15:53
@hlxid hlxid force-pushed the feat/encrypt-using-password-hash branch from fb47e57 to f93a6fe Compare August 15, 2022 09:15
@hlxid hlxid changed the title Derive encryption key in dashboard using PBKDF2 Derive encryption key in dashboard using Argon2 Aug 24, 2022
The latest official release argon2-browser doesn't support node.js v18+
and also has some other caveats.
Because of this I've used my fork of it in 74099d4
with some patches.
Instead of using my patched version this commit uses hash-wasm which
also includes a implementation of argon2, works correctly with node.js
v18 and works fine in the browser as well.
@hlxid hlxid force-pushed the feat/encrypt-using-password-hash branch from 4f70456 to ef05ddd Compare October 12, 2022 08:47
@hlxid hlxid force-pushed the feat/encrypt-using-password-hash branch from ef05ddd to 40ac791 Compare October 12, 2022 09:01
@hlxid
Copy link
Member Author

hlxid commented Oct 12, 2022

This PR is finally ready to be merged. @sebinside could you please re-review this?

@hlxid hlxid added this to the v0.3.0 milestone May 1, 2023
@hlxid hlxid merged commit 8eea596 into main Jul 23, 2023
@hlxid hlxid deleted the feat/encrypt-using-password-hash branch July 23, 2023 18:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants