Competely reset and re-do server-side encryption

Hi all,

Firstly, please excuse me if I sound a bit exasperated. So… some time back I reluctantly enabled Server Side Encryption to support two modules that required it (passwords and otpmanager).

I neglected to set up a recovery key (my fault), and I have a user that has forgotten their password. Except, I cannot change the password: in the admin UI, there’s no means to change the user’s password, the user has no email address set (so they can’t use the “forgot password”), and I can’t set an email address (it just ignores me and the email field stays blank … nothing in the logs).

From the command line, occ user:resetpassword prompts “are you sure”, I answer y, and type a new password in twice at its request (not an existing password, a new password)… then it complains maybe I “provided the wrong password”.

host:~# occ user:resetpassword theuser
{"reqId":"OW5LEXZQHBQzej0B1Siy","level":1,"time":"2025-05-04T04:25:44+00:00","remoteAddr":"","user":"--","app":"admin_audit","method":"","url":"--","message":"Console command executed: user:resetpassword theuser","userAgent":"--","version":"30.0.8.1","data":{"app":"admin_audit"}}
Warning: Resetting the password when using encryption will result in data loss!
Do you want to continue?y
Enter a new password: 
Confirm the new password: 
Can not decrypt the recovery key. Maybe you provided the wrong password. Try again.

How? It asked for a new password, I gave it a new password. How does it know it is “wrong”? It didn’t ask for a recovery key, it asked for a new password, which by definition of being new, is not known to the system in any way shape or form. Otherwise it wouldn’t be a new password would it?

If it wants an existing secret, it should ask for the existing secret, and not a new one.

So clearly, it is trying to recover a secret encrypted with a password no one has. Easiest thing, is to take back-ups of the critical files, then blow the lot away and re-start. Accept the loss and move on.

I’ve taken a back-up of all encrypted files: in my password manager (pass) I have JSON back-ups of the data from passwords and otpmanager. I am willing to destroy all encrypted data in the server and re-create them from these back-ups.

I tried doing a occ encryption:disable then an occ encryption:enable … somehow when I re-load passwords or otpmanager in my browser, the secrets persist, so clearly that did not delete the encrypted data like it ought to have.

So the question, how do I restore this system to a state of “has no encrypted data”, so that I can generate new root encryption secrets, set up a new recovery key, re-import the exported backups, and re-share these secrets and finally reset this guy’s password?

Alternatively, is there a way to blow away and re-create the user’s “recovery key”? Again, the only thing encrypted is these passwords and TOTP secrets, I can re-share them with the user. Nothing will be lost that isn’t recoverable by other means external to NextCloud. How do I reset this?

1 Like

Still working on this.

I did find there was a occ passwords:user:delete … tried this with no improvement to the situation.

Now, apparently I can enable a master key if the installation is “new” (that boat sailed years ago back when the server ran OwnCloud 6.x) or when there is “no existing encrypted data”.

The latter seems to be the way forward. How do I make this server have “no existing encrypted data”? Make the existing “encrypted data” vanish.

In the nextcloud.log file, I see the following (re-formatted for readability):

{
  "reqId": "AN6x9yXmqU6mY0AmO8cr",
  "level": 3,
  "time": "2025-05-04T06:01:59+00:00",
  "remoteAddr": "",
  "user": "--",
  "app": "no app in context",
  "method": "",
  "url": "--",
  "message": "Exception thrown: OCP\\Encryption\\Exceptions\\GenericEncryptionException",
  "userAgent": "--",
  "version": "30.0.8.1",
  "exception": {
    "Exception": "OCP\\Encryption\\Exceptions\\GenericEncryptionException",
    "Message": "Can not decrypt the recovery key. Maybe you provided the wrong password. Try again.",
    "Code": 0,
    "Trace": [
      {
        "file": "/usr/share/webapps/nextcloud/lib/private/legacy/OC_Hook.php",
        "line": 82,
        "function": "setPassphrase",
        "class": "OCA\\Encryption\\Hooks\\UserHooks",
        "type": "->",
        "args": [
          "*** sensitive parameters replaced ***"
        ]
      },
      {
        "file": "/usr/share/webapps/nextcloud/lib/private/Server.php",
        "line": 539,
        "function": "emit",
        "class": "OC_Hook",
        "type": "::"
      },
      {
        "function": "OC\\{closure}",
        "class": "OC\\Server",
        "type": "->",
        "args": [
          "*** sensitive parameters replaced ***"
        ]
      },
      {
        "file": "/usr/share/webapps/nextcloud/lib/private/Hooks/EmitterTrait.php",
        "line": 88,
        "function": "call_user_func_array"
      },
      {
        "file": "/usr/share/webapps/nextcloud/lib/private/Hooks/PublicEmitter.php",
        "line": 22,
        "function": "emit",
        "class": "OC\\Hooks\\BasicEmitter",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/lib/private/User/User.php",
        "line": 339,
        "function": "emit",
        "class": "OC\\Hooks\\PublicEmitter",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/core/Command/User/ResetPassword.php",
        "line": 103,
        "function": "setPassword",
        "class": "OC\\User\\User",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/3rdparty/symfony/console/Command/Command.php",
        "line": 326,
        "function": "execute",
        "class": "OC\\Core\\Command\\User\\ResetPassword",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/core/Command/Base.php",
        "line": 161,
        "function": "run",
        "class": "Symfony\\Component\\Console\\Command\\Command",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/3rdparty/symfony/console/Application.php",
        "line": 1078,
        "function": "run",
        "class": "OC\\Core\\Command\\Base",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/3rdparty/symfony/console/Application.php",
        "line": 324,
        "function": "doRunCommand",
        "class": "Symfony\\Component\\Console\\Application",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/3rdparty/symfony/console/Application.php",
        "line": 175,
        "function": "doRun",
        "class": "Symfony\\Component\\Console\\Application",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/lib/private/Console/Application.php",
        "line": 183,
        "function": "run",
        "class": "Symfony\\Component\\Console\\Application",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/console.php",
        "line": 87,
        "function": "run",
        "class": "OC\\Console\\Application",
        "type": "->"
      },
      {
        "file": "/usr/share/webapps/nextcloud/occ",
        "line": 33,
        "args": [
          "/usr/share/webapps/nextcloud/console.php"
        ],
        "function": "require_once"
      }
    ],
    "File": "/usr/share/webapps/nextcloud/apps/encryption/lib/Hooks/UserHooks.php",
    "Line": 210,
    "Hint": "Can not decrypt the recovery key. Maybe you provided the wrong password. Try again.",
    "CustomMessage": "Exception thrown: OCP\\Encryption\\Exceptions\\GenericEncryptionException"
  }
}

Where is this “recovery key”? It isn’t in /data/theuser/files_encryption … that directory does not exist, and has never existed. I went hunting in the SQL database dump and didn’t see it there either.

The admin user has a files_encryption directory, but not the user who’s password I need to reset. Still, NextCloud insists it needs to decrypt “the” recovery key. What key? Where? Why? Just delete it and move on already.

The issue isn’t “solved” but I managed to reset the user’s password by going behind NextCloud’s back.

In the database (MariaDB in my case) there’s a table oc_users with a uid field corresponding to the username and a password field being a password hash.

The newest passwords seemed to be Argon2ID with a 3| prefixed. I used ipython and the argon2 module to generate a new password hash with a known password then did a SQL UPDATE to directly inject it into the oc_users table.

Now I can log in as that user… and I’ll re-set up the sharing I had with that user.

1 Like

Well, just a thought. Does the User who lost his Password do own a backup of all the data stored in the Nextcloud?

You have had spend a lot of time so far,just to reset the password. If there is a recent backup most likely it would have done faster just to delete the User and create a new one, then restore the files from Backup into the new created User-Acoount.

I should be able to change the password of an existing user without deleting and re-creating the user. Whether or not they have backups of their data is irrelevant.

If that means we have to re-create secret keys and lose access to old data, so be it. I’m willing to accept that compromise … but I’m not allowed to do that because I Might Lose Data.

Yeah, that data is lost, I accept that loss. I should not have to delete and re-create a whole user just because a key feature (password reset) is broken.

This is like buying a whole new car because the existing one developed a flat tyre.

1 Like

They said it is not required:

The server-side encryption is designed for external storage. For the users that use local storage (many), you only add a lot of complexity to the whole system without the benefits.
It would be really bad practice, if an app required you to enable it no matter what storage you use.

For me that means that the new password and the confirmation of the password do not match. However, that does not match with the message about the recovery key. Like this it looks like a bug, and should probably be reported to GitHub · Where software is built

You have locally the unencrypted backup of the data. Then you create a new user, sync to an new and empty folder on the local machine. Then you copy the file from your backup into this sync folder and let the client sync.

Especially with the server-side encryption, I would be very careful. Passwords have salts from the config file, individual encrypted files take information from the database to verify the content.

I was able to install both apps without server-side encryption module enabled.

They said it is not required

ICrypto interface is the encryption module is it not? In any case, it was installing the two of these. passwords and otpmanager that triggered this feature requirement. Bad practice or not, it happened. I’ve had the modules installed nearly a year now, I had not needed this prior to then.

The Encryption features in NextCloud settings aren’t clear about what they encrypt … it seemed like a base encryption feature for database field and file encryption, thus it seemed logical that it would be required for encrypting secrets stored in the database.

For me that means that the new password and the confirmation of the password do not match.

Unless there is a bug in Konsole / the X11 clipboard / OpenSSH that only happens when interacting with occ via SSH, I find this an improbable explanation.

You have locally the unencrypted backup of the data. Then you create a new user, sync to an new and empty folder on the local machine. Then you copy the file from your backup into this sync folder and let the client sync.

So I do it for the affected user, but what about everyone else I had shared the password manager passwords with? Bearing in mind that the encrypted data is not stored as files, it’s a field in the database, and very few of us are using file synchronisation clients. (The user in question definitely is not, and has not logged in for over a year.)

It’s sounding like a “blow the whole instance away” since the files are not encrypted, the encrypted fields are in the database. I then have to figure out how to filter these encrypted fields from the database back-up when restoring.

Especially with the server-side encryption, I would be very careful. Passwords have salts from the config file, individual encrypted files take information from the database to verify the content.

Yeah, I do not like fiddling around in a database as I was conscious of key derivation functions that might break due to me changing the password. Hence I was looking for a function that would clear these without destroying the user account.

I was able to install both apps without server-side encryption module enabled.

If this is the case, I should be able to run occ encryption:disable and rid myself of the whole problem.

You need to unencrypt everything before you disable encryption. It is not just to disable. All the files users stores when encryption is on will be encrypted.

Read this before you fiddle with anything:

You need to unencrypt everything before you disable encryption. It is not just to disable. All the files users stores when encryption is on will be encrypted.

I don’t want to keep the encrypted data, I want to delete it.

Just so you are aware that those files cant be recovered even from backup. So if you destroy them they will be gone. Simplest way is to run decrypt all and then disable anyway.

Just so you are aware that those files cant be recovered even from backup. So if you destroy them they will be gone. Simplest way is to run decrypt all and then disable anyway.

The passwords and TOTP secrets are backed up safely. I have them as JSON dumps encrypted with OpenPGP and stored in git (thanks to pass).

I do not want to decrypt them, I want to delete them.

Not sure, perhaps they can use the module for the app data only (and without encrypting the storage)?
If you mainly use your setup to share passwords, it probably won’t matter that much.