Skip to content

Conversation

@mikesposito
Copy link
Member

@mikesposito mikesposito commented Nov 12, 2025

Explanation

This PR extracts the second and final set of changes from #5963, which refactors the KeyringController to always derive the encryption key from the password, rather than storing it in memory.

This change allows to simplify #unlockKeyrings and #updateVault methods, after the removeal of all the logic and tests related to cacheEncryptionKey. This also allows to remove this.#password, that has been replaced by this.#encryptionKey.

The this.#encryptionKey assignment logic has been moved to two new internal methods with these specific responsibilities:

  • #deriveEncryptionKey(string): Derives the encryption key from the password, to be used during password login and password change.
  • #useEncryptionKey(string, string): Uses an existing encryption key to be used directly, to be used by submitEncryptionKey mainly.

Package previews from this branch are tested on clients with these PRs:

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

Note

Refactors vault encryption in KeyringController to derive/use a serialized encryption key (not password), adds required encryptor methods, updates tests, and bumps browser-passworder to v6.

  • Keyring Controller:
    • Refactor encryption flow to always derive and cache a serialized encryptionKey with salt; remove password caching and related logic.
    • Introduce #deriveAndSetEncryptionKey and #setEncryptionKey; rework submitPassword, submitEncryptionKey, changePassword, #updateVault, and #unlockKeyrings to use imported/exported keys.
    • Add WrongEncryptionKeyType error; persist encryptionKey/encryptionSalt consistently; remove use of old cached-key upgrade path.
    • Expand Encryptor interface to require exportKey, keyFromPassword, and generateSalt.
  • Tests:
    • Large updates to align with new encryption flow (password change, unlock, metadata upgrades, error cases); adjust mocks to support new encryptor methods.
    • Increase coverage thresholds in jest.config.js.
  • Seedless Onboarding:
    • Update default/mock encryptors to include exportKey, keyFromPassword, generateSalt; adapt tests accordingly.
  • Dependencies:
    • Bump @metamask/browser-passworder to ^6.0.0 in affected packages.
    • Update yarn.lock accordingly.

Written by Cursor Bugbot for commit 7b3eef0. This will update automatically on new commits. Configure here.

@mikesposito
Copy link
Member Author

@metamaskbot publish-preview

@github-actions
Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "3.0.0-preview-cb2e5c04",
  "@metamask-previews/accounts-controller": "34.0.0-preview-cb2e5c04",
  "@metamask-previews/address-book-controller": "7.0.0-preview-cb2e5c04",
  "@metamask-previews/analytics-controller": "0.0.0-preview-cb2e5c04",
  "@metamask-previews/announcement-controller": "8.0.0-preview-cb2e5c04",
  "@metamask-previews/app-metadata-controller": "2.0.0-preview-cb2e5c04",
  "@metamask-previews/approval-controller": "8.0.0-preview-cb2e5c04",
  "@metamask-previews/assets-controllers": "88.0.0-preview-cb2e5c04",
  "@metamask-previews/base-controller": "9.0.0-preview-cb2e5c04",
  "@metamask-previews/bridge-controller": "60.0.0-preview-cb2e5c04",
  "@metamask-previews/bridge-status-controller": "60.0.0-preview-cb2e5c04",
  "@metamask-previews/build-utils": "3.0.4-preview-cb2e5c04",
  "@metamask-previews/chain-agnostic-permission": "1.2.2-preview-cb2e5c04",
  "@metamask-previews/claims-controller": "0.2.0-preview-cb2e5c04",
  "@metamask-previews/composable-controller": "12.0.0-preview-cb2e5c04",
  "@metamask-previews/controller-utils": "11.15.0-preview-cb2e5c04",
  "@metamask-previews/core-backend": "4.0.0-preview-cb2e5c04",
  "@metamask-previews/delegation-controller": "1.0.0-preview-cb2e5c04",
  "@metamask-previews/earn-controller": "10.0.0-preview-cb2e5c04",
  "@metamask-previews/eip-5792-middleware": "2.0.0-preview-cb2e5c04",
  "@metamask-previews/eip-7702-internal-rpc-middleware": "0.1.0-preview-cb2e5c04",
  "@metamask-previews/eip1193-permission-middleware": "1.0.2-preview-cb2e5c04",
  "@metamask-previews/ens-controller": "18.0.0-preview-cb2e5c04",
  "@metamask-previews/error-reporting-service": "3.0.0-preview-cb2e5c04",
  "@metamask-previews/eth-block-tracker": "14.0.0-preview-cb2e5c04",
  "@metamask-previews/eth-json-rpc-middleware": "21.0.0-preview-cb2e5c04",
  "@metamask-previews/eth-json-rpc-provider": "5.0.1-preview-cb2e5c04",
  "@metamask-previews/foundryup": "1.0.1-preview-cb2e5c04",
  "@metamask-previews/gas-fee-controller": "25.0.0-preview-cb2e5c04",
  "@metamask-previews/gator-permissions-controller": "0.4.0-preview-cb2e5c04",
  "@metamask-previews/json-rpc-engine": "10.1.1-preview-cb2e5c04",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.8-preview-cb2e5c04",
  "@metamask-previews/keyring-controller": "24.0.0-preview-cb2e5c04",
  "@metamask-previews/logging-controller": "7.0.0-preview-cb2e5c04",
  "@metamask-previews/message-manager": "14.0.0-preview-cb2e5c04",
  "@metamask-previews/messenger": "0.3.0-preview-cb2e5c04",
  "@metamask-previews/multichain-account-service": "3.0.0-preview-cb2e5c04",
  "@metamask-previews/multichain-api-middleware": "1.2.4-preview-cb2e5c04",
  "@metamask-previews/multichain-network-controller": "2.0.0-preview-cb2e5c04",
  "@metamask-previews/multichain-transactions-controller": "6.0.0-preview-cb2e5c04",
  "@metamask-previews/name-controller": "9.0.0-preview-cb2e5c04",
  "@metamask-previews/network-controller": "25.0.0-preview-cb2e5c04",
  "@metamask-previews/network-enablement-controller": "3.1.0-preview-cb2e5c04",
  "@metamask-previews/notification-services-controller": "19.0.0-preview-cb2e5c04",
  "@metamask-previews/permission-controller": "12.1.0-preview-cb2e5c04",
  "@metamask-previews/permission-log-controller": "5.0.0-preview-cb2e5c04",
  "@metamask-previews/phishing-controller": "15.0.0-preview-cb2e5c04",
  "@metamask-previews/polling-controller": "15.0.0-preview-cb2e5c04",
  "@metamask-previews/preferences-controller": "21.0.0-preview-cb2e5c04",
  "@metamask-previews/profile-sync-controller": "26.0.0-preview-cb2e5c04",
  "@metamask-previews/rate-limit-controller": "7.0.0-preview-cb2e5c04",
  "@metamask-previews/remote-feature-flag-controller": "2.0.0-preview-cb2e5c04",
  "@metamask-previews/sample-controllers": "3.0.0-preview-cb2e5c04",
  "@metamask-previews/seedless-onboarding-controller": "6.1.0-preview-cb2e5c04",
  "@metamask-previews/selected-network-controller": "25.0.0-preview-cb2e5c04",
  "@metamask-previews/shield-controller": "2.0.0-preview-cb2e5c04",
  "@metamask-previews/signature-controller": "36.0.0-preview-cb2e5c04",
  "@metamask-previews/subscription-controller": "4.0.0-preview-cb2e5c04",
  "@metamask-previews/token-search-discovery-controller": "4.0.0-preview-cb2e5c04",
  "@metamask-previews/transaction-controller": "61.1.0-preview-cb2e5c04",
  "@metamask-previews/transaction-pay-controller": "4.0.0-preview-cb2e5c04",
  "@metamask-previews/user-operation-controller": "40.0.0-preview-cb2e5c04"
}

@mikesposito mikesposito force-pushed the mikesposito/keyring-controller/never-use-password branch from 8f04566 to ad1ae0d Compare November 12, 2025 10:22
state.encryptionSalt = updatedState.encryptionSalt;
}
state.encryptionKey = encryptionKey;
state.encryptionSalt = parsedEncryptedVault.salt;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think there is a potential bug here:
Above you set

        this.#setEncryptionKey(
          credentials.encryptionKey,
          credentials.encryptionSalt || parsedEncryptedVault.salt,
        );

but here you set

state.encryptionSalt = parsedEncryptedVault.salt;

Shouldn't this be:

state.encryptionSalt = this.#encryptionKey.salt;

Copy link
Member Author

Choose a reason for hiding this comment

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

As we are decrypting the vault here, the existing vault salt and this.#encryptionKey.salt should always be the same, even when the salt is undefined, right?

Copy link
Member

@Gudahtt Gudahtt Nov 12, 2025

Choose a reason for hiding this comment

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

Yeah, we have a check to ensure they are the same in #setEncryptionKey. See where we throw the KeyringControllerError.ExpiredCredentials error.

Though... it is a bit confusing that the guarantee about these being the same is in a different function 🤔. Perhaps it would be simplest to use this.#encryptionKey.salt; just so the reader doesn't need to understand where it was validated?

Potentially a slight readability improvement here, but I don't think it's a bug

Copy link
Member Author

Choose a reason for hiding this comment

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

That makes sense. I was being conservative on what was there before, but I agree that using this.#encryptionKey.salt is clearer, and should be equivalent. Done in c59a9c1

Base automatically changed from mikesposito/keyring-controller/remove-cache-encryption-key to main November 12, 2025 14:33
@mikesposito mikesposito force-pushed the mikesposito/keyring-controller/never-use-password branch from 5f8200d to 54baecf Compare November 12, 2025 18:33
@mikesposito mikesposito marked this pull request as ready for review November 12, 2025 18:36
@mikesposito mikesposito requested review from a team as code owners November 12, 2025 18:36
@socket-security
Copy link

socket-security bot commented Nov 12, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​metamask/​browser-passworder@​4.3.0 ⏵ 6.0.010010010084 +3100

View full report

@mikesposito
Copy link
Member Author

@metamaskbot publish-preview

@github-actions
Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "3.0.0-preview-20df3e99",
  "@metamask-previews/accounts-controller": "34.0.0-preview-20df3e99",
  "@metamask-previews/address-book-controller": "7.0.0-preview-20df3e99",
  "@metamask-previews/analytics-controller": "0.0.0-preview-20df3e99",
  "@metamask-previews/announcement-controller": "8.0.0-preview-20df3e99",
  "@metamask-previews/app-metadata-controller": "2.0.0-preview-20df3e99",
  "@metamask-previews/approval-controller": "8.0.0-preview-20df3e99",
  "@metamask-previews/assets-controllers": "88.0.0-preview-20df3e99",
  "@metamask-previews/base-controller": "9.0.0-preview-20df3e99",
  "@metamask-previews/bridge-controller": "60.1.0-preview-20df3e99",
  "@metamask-previews/bridge-status-controller": "60.1.0-preview-20df3e99",
  "@metamask-previews/build-utils": "3.0.4-preview-20df3e99",
  "@metamask-previews/chain-agnostic-permission": "1.2.2-preview-20df3e99",
  "@metamask-previews/claims-controller": "0.2.0-preview-20df3e99",
  "@metamask-previews/composable-controller": "12.0.0-preview-20df3e99",
  "@metamask-previews/controller-utils": "11.15.0-preview-20df3e99",
  "@metamask-previews/core-backend": "4.0.0-preview-20df3e99",
  "@metamask-previews/delegation-controller": "1.0.0-preview-20df3e99",
  "@metamask-previews/earn-controller": "10.0.0-preview-20df3e99",
  "@metamask-previews/eip-5792-middleware": "2.0.0-preview-20df3e99",
  "@metamask-previews/eip-7702-internal-rpc-middleware": "0.1.0-preview-20df3e99",
  "@metamask-previews/eip1193-permission-middleware": "1.0.2-preview-20df3e99",
  "@metamask-previews/ens-controller": "18.0.0-preview-20df3e99",
  "@metamask-previews/error-reporting-service": "3.0.0-preview-20df3e99",
  "@metamask-previews/eth-block-tracker": "14.0.0-preview-20df3e99",
  "@metamask-previews/eth-json-rpc-middleware": "21.0.0-preview-20df3e99",
  "@metamask-previews/eth-json-rpc-provider": "5.0.1-preview-20df3e99",
  "@metamask-previews/foundryup": "1.0.1-preview-20df3e99",
  "@metamask-previews/gas-fee-controller": "25.0.0-preview-20df3e99",
  "@metamask-previews/gator-permissions-controller": "0.4.0-preview-20df3e99",
  "@metamask-previews/json-rpc-engine": "10.1.1-preview-20df3e99",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.8-preview-20df3e99",
  "@metamask-previews/keyring-controller": "24.0.0-preview-20df3e99",
  "@metamask-previews/logging-controller": "7.0.0-preview-20df3e99",
  "@metamask-previews/message-manager": "14.0.0-preview-20df3e99",
  "@metamask-previews/messenger": "0.3.0-preview-20df3e99",
  "@metamask-previews/multichain-account-service": "3.0.0-preview-20df3e99",
  "@metamask-previews/multichain-api-middleware": "1.2.4-preview-20df3e99",
  "@metamask-previews/multichain-network-controller": "2.0.0-preview-20df3e99",
  "@metamask-previews/multichain-transactions-controller": "6.0.0-preview-20df3e99",
  "@metamask-previews/name-controller": "9.0.0-preview-20df3e99",
  "@metamask-previews/network-controller": "25.0.0-preview-20df3e99",
  "@metamask-previews/network-enablement-controller": "3.1.0-preview-20df3e99",
  "@metamask-previews/notification-services-controller": "19.0.0-preview-20df3e99",
  "@metamask-previews/permission-controller": "12.1.0-preview-20df3e99",
  "@metamask-previews/permission-log-controller": "5.0.0-preview-20df3e99",
  "@metamask-previews/phishing-controller": "15.0.0-preview-20df3e99",
  "@metamask-previews/polling-controller": "15.0.0-preview-20df3e99",
  "@metamask-previews/preferences-controller": "21.0.0-preview-20df3e99",
  "@metamask-previews/profile-sync-controller": "26.0.0-preview-20df3e99",
  "@metamask-previews/rate-limit-controller": "7.0.0-preview-20df3e99",
  "@metamask-previews/remote-feature-flag-controller": "2.0.0-preview-20df3e99",
  "@metamask-previews/sample-controllers": "3.0.0-preview-20df3e99",
  "@metamask-previews/seedless-onboarding-controller": "6.1.0-preview-20df3e99",
  "@metamask-previews/selected-network-controller": "25.0.0-preview-20df3e99",
  "@metamask-previews/shield-controller": "2.0.0-preview-20df3e99",
  "@metamask-previews/signature-controller": "36.0.0-preview-20df3e99",
  "@metamask-previews/subscription-controller": "4.2.1-preview-20df3e99",
  "@metamask-previews/token-search-discovery-controller": "4.0.0-preview-20df3e99",
  "@metamask-previews/transaction-controller": "61.2.0-preview-20df3e99",
  "@metamask-previews/transaction-pay-controller": "5.0.0-preview-20df3e99",
  "@metamask-previews/user-operation-controller": "40.0.0-preview-20df3e99"
}

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.

[KeyringController] Drop uncached encryption support

5 participants