KeePass, Keeweb with OneDrive and Dropbox

Introduction

This blog describes some hints to get a self hosted Keeweb working with a KeePass database files stored on Microsoft OneDrive or Dropbox.

KeePass is an open source password manager. It is a PC application storing your credentials and secrets in an encrypted .kdbx database file. I use it for some time now and I am happy with it. I started to use it with my database on a memory stick, to have it anywhere I go. This, however, is not a fine way of working, because I tend to forget my memory stick. So I wondered if I could use my KeePass database in a self hosted web based application. I did some searching around and found Keeweb to be most applicable.

KeePass

Keeweb comes in a desktop application as well as a web application. The latter seems to be about what I want.

Keeweb web application

However, I like to be in control and host the application myself. I finally succeeded to get it working with my KeePass database on Microsoft OneDrive and and on Dropbox. There are two sites I would like to mention that provide a howto.

Why then, this blog as third howto? Well, following both links still gave me some head-aches. Therefore I report my findings

Cyber security

First a word about security. I did some analysis to have an indication about whether accessing your personal secrets from a web application and storing them in the cloud is a sensible thing to do. Here are my findings.

KeePass database encryption

First of course there is the KeePass database. Reading a bit about the .kdbx file format I get a good impression about the security of the application. In order to get some hands-on experience, I wrote a decryption program, which you can find on my github. The program decrypts and decodes KeePass test databases protected with a master password into its XML content. I even tested the security by writing a small brute-force algorithm.

Note that the .kdbx format comes into two versions: 3.x and 4. Both versions are supported by Keeweb!

In version 3 AES/CBC with PKCS5 padding is used for (symmetric) encryption of the database. This is an encryption that has not been cracked and it regarded as safe against brute-force attacks. The CBC variant, using an Initialization Vector (IV) is regarded as best practice over ECB. In version 4 ChaCha20 has been added as an alternative streaming encryption. This seems to be a pretty strong algorithm.

The process of decrypting a KeePass database (.kdbx version 3.1). See my github page.

In version 3.x the symmetric master key to AES encrypt/decrypt the database is generated in a complex way based on the master password or key file provided by the user (the key transformation process or Key Derivation Function KDF). This generation process encompasses multiple times of SHA256 hashing, a variable number (60.000; can be increased in the KeePass settings) of AES/ECB encryptions and salting. The major advantage of this (especially the 60.000 encryption rounds) is that it takes some time (~ 1 ms). Therefore brute force attacking becomes harder. Things like salting with a salt that is enclosed in the .kdbx file does not make much sense to me and looks more like security-by-obscurity. (Note that algorithms and algorithm settings can be changed in the KeePass settings).

Using my brute force attack Java program, using one thread (hence not very efficient), on my Core I5-9600k @ 3.7 GHz (one thread means one core) I can test about 400 passwords per second. This means a password of 4 characters can be cracked in maximum 10 hours, assuming only letters (lowercase and uppercase) and numbers (2x 26+10 = 62 possible characters). In fact, in the example below it took 3:10 hours to find the password ‘test’. So be sure to choose a sufficiently strong master password, given the diagram below.

Based on the brute force simulation the time to crack the Master Password vs number of characters
...
2023-01-18 10:23:38 INFO Testing tesp
2023-01-18 10:23:38 ERROR Error decrypting database: Bad Padding: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
2023-01-18 10:23:38 INFO Testing tesq
2023-01-18 10:23:38 ERROR Error decrypting database: Bad Padding: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
2023-01-18 10:23:38 INFO Testing tesr
2023-01-18 10:23:38 ERROR Error decrypting database: Bad Padding: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
2023-01-18 10:23:38 INFO Testing tess
2023-01-18 10:23:38 ERROR Error decrypting database: Bad Padding: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
2023-01-18 10:23:38 INFO Testing test
2023-01-18 10:23:38 INFO Password found: test
2023-01-18 10:23:38 INFO It took 11427 seconds

It is easy to speed up such a brute force attack a factor of 100 or 1000 by employing more cores, more efficient programming or using compute in the cloud, but it still would take ages (literally) to crack a password of 10 characters.

Note that brute forcing is not very efficient. Programs like John the Ripper are much smarter and try passwords that are popular or follow popular patterns. Simple or weak passwords are cracked within seconds. To crack a database using John the Ripper run:

keepass2john test.kdbx > hash.txt
john hash.txt

A note on the .kdbx version 4. This version adds the Argon2d and Argon2id password hash algorithms for the Key Derivation Function (KDF). These algorithms can better withstand brute forcing, since they require significant resources of the platform. With default parameters, calculating a hash on my Core I5 takes about 200 ms (i.e. you can test 5 passwords per second)

Passwords/secrets within the XML database are still encrypted using a second layer of encryption. So given the plain-text XML, passwords are still not visible. I think this is good practice, since when you consult your credentials, you usually are interested in just one password. So you decrypt only the one you need and not every one of them. If adversaries happen to gain access to the plain-text database file, passwords/secrets are not visible (though knowing how KeePass works, it wouldn’t be that hard to decrypt them…)

However…. In order to decrypt the one password you need to decrypt all passwords sequentially up to the password you need. The Salsa20/RC4 decryption engine needs to be initialized once instead of before each password decryption!
The advantage this is that identical passwords (in plain-text) lead to different encryptions.
The disadvantage is that you have to decrypt all passwords instead of only the one you need.
I am not sure what is better…

Finally, I believe in open source: having the algorithms exposed to the community, a lot of experts look at it. Vulnerabilities will be recognized and repaired more easily than with closed source. And it prevents security-by-obscurity: good security does not rely on hiding the source code or algorithms.

So I believe KeePass is sufficiently secure, provided that a sufficiently strong password (10 characters at least, lower case, upper case characters, numbers, etc) is used by the user.

Minor flaw: The KeePass .kdbx 3.x file contains in the header the first unencrypted 32 bytes of the payload (which are random bytes, not part of your credentials). It can be used to validate the result after decryption with the master key. It is nice for the KeePass software to validate the payload and decryption process. However, it is also handy for the hacker when brute forcing: it can be used to check whether a tested password results in properly decrypted payload (without processing the payload any further)! John the Ripper uses these bytes.
In .kdbx 4, a master password can be tested by checking the HMAC SHA256 hash of the header. This requires a key that is derived from the master password.

Your KeePass database in the cloud

Storing your KeePass database in the cloud might sound pretty scary, because you hand over all your credentials to a cloud service provider. However, since the encryption of the KeePass database is secure, I dare to store the database in the cloud. If the cloud is compromised (which is highly unlikely) and adversaries steal your database, the KeePass encryption is the 2nd line of defense.

I would encourage to rename your KeePass database file to .bin instead of .kdbx and do not use filenames like mycredentials or passwords. Though might seem like security-by-by-obscurity, it makes it harder to recognize the nature of the file or the file format. So a file like image.bin is harder to find and analyse than passwords.kdbx. Adversaries typically scan for files like password*.*, passport.jpg or *.kdbx when they hack your computer. So don’t make it easy too easy for them. (Of course, a hacker can recognize a KeePass database file by the first 8 bytes of the file, which are the KeePass signature.)

Companies like Google (Google Drive) and Microsoft (OneDrive) have strong access security in place, which I dare to trust. Access is via two factor authentication. If their security measures wouldn’t be good enough, they would be out of business quite soon. I have two employers who are very security aware and they provide OneDrive as secure storage to us employees. Dropbox however, is forbidden by them. I wouldn’t use Dropbox for that reason.

Keeweb: web based access

Generally speaking, the decryption process most vulnerable at two points:

  • At entering the master password for decryption – can adversaries intercept your master password?
  • When the database is decrypted and stored for further processing – can adversaries intercept the plain-text database?

Analysing network traffic shows:

  • The Keeweb application consists of HTML code and Javascript. It is download entirely as one huge html file to your PC. It runs in your browser.
  • Keeweb accesses your KeePass database from Google Drive, OneDrive or Dropbox. The database is downloaded locally to your browser. There it is decrypted using the master password you enter. After modification the file is encrypted again and uploaded to the cloud.
  • Of course https is used for transfer from and to the cloud. Therefore the database is double encrypted in transit.

This means, all file access is done locally. Your master password never leaves your computer, nor does your decrypted database. I did not find where the decrypted database is stored in the browser, so it probably is stored in memory, as a javascript variable.

Because neither the password nor the plain-text database leaves your browser, chances are pretty low that they can be intercepted by adversaries.

The only flaw I found is that your OAuth application secrets are revealed in the Keeweb configuration file config.json. This file is stored on the websever and can be requested from any browser on the world. Of course these secrets are not enough to access your files, but it is one step towards it.
To mitigate this risk you might apply basic authentication to your Keeweb site (except for the /oauth-result directory!!). This means you have to logon with username and password to access your Keeweb site. At your webserver the configuration file should be only accessible to your webserver and not to anyone else.

Another remarkable finding about Keeweb: as is described on my github page, the master key for encryption/decryption is derived from the master password and/or key file entered by the user by means of a fairly complex process. KeePass uses amongst others by default 60.000 rounds of AES/ECB encryption in .kdbx version 3.x. When Keeweb encrypts the .kdbx database, it reduces this number to 6.000 rounds!!!, making brute force attacking a little bit easier. Apparently it does not take the setting properly from the database.
Therefor, use Argon2d or Argon2id over AES/ECB as Key Derivation Function.

Conclusion

Based on these findings I have confidence in the security of accessing my KeePass database using Keeweb. However, this of course is not a full vulnerability scan or pen test.

Summarizing, best practices I would recommend:

  • First and for all: Use a sufficiently strong master password for your KeePass database.
  • Use argon2d or argon2id as password hashing algorithms (hence .kdbx 4). Open your database in Keepass, you’ll find it under Database Settings, Security, Key Transformation
  • When hosting Keeweb, make sure it is protected, for example using basic authentication
  • Store your KeePass database on Microsoft Onedrive or Google Drive, using 2FA for access
  • Rename your database file to something that does not give away the nature of the file nor its format.
  • Run Keeweb in an incognito Window, so nothing is stored permanently
  • Close the browser after usage, so anything in memory is cleared

Howto

General

The latest release of Keeweb for hosting is a little bit hidden. Here is the link. Unzip the file on your web server of choice. You can also deploy as docker container. Refer to the github pages.

We are going to use the configuration file config.json in the root of Keeweb. For this you have to open the index.html (which is obfuscated and minified) and change a meta value kw-config an give it following value:

<meta name="kw-config" content="./config.json">

The application will now look for the configuration file ./config.json.

OAuth 2.0

Systems like Microsoft OneDrive, Dropbox and Google Drive use OAuth 2.0 as the protocol for authentication and authorization. This section gives a small introduction.

In OAuth the process is roughly as follows:

  1. the Application (Keeweb) requests access to a resource (in casu: files on the drive in the cloud) on behalf of the Application User. This access is requested to the Authorization Server of Microsoft/Google/Dropbox. For Microsoft the Authorization Server is Azure Active Directory.
  2. The Authorization Server validates the identity of the Application User. This is usually done by means of a pop-up in which the user can login with username and password and optionally two factor authentication.
  3. The Authorization Server indicates the rights (claims) that will be granted to the Application and asks the Application User consent.
  4. The Authorization Server grants the access to the Application on behalf of the user by means of a signed token containing the identity and claims of the user.
  5. The Application accesses the Resource (files on the OneDrive/Dropbox/GoogleDrive) using the token.
  6. The Resource Server validates the token and provides the Resource.

In order for this to work there are a few things that must be arranged:

  1. The Application must be registered with the Authorization Server. Usually the Authorization Server provides the Application with an ID and secret to be used during the access request.
  2. The Application must be granted the appropriate rights, for example the right to read and write files. Apply the principle of ‘least-privilege’: grant sufficient rights but not more than that
  3. The Application must provide a redirect URL to which the token will be send. This URL must be stored with the registration.

In OAuth 2.0 there are several flows and flavours, like the code-grant flow or client-credentials flow. It is not the intention of this section to be complete on this.

OneDrive

Prerequisite:

  • You have a Microsoft account for Microsoft 365
  • You have access to Azure AD (which I guess comes with your Microsoft account)

Steps to take:

First register your Keeweb web app in Azure AD:

  1. Log in on the Azure portal

  2. Choose Azure Active Directory from the menu, choose App Registrations, then choose New Registration



  3. Enter a name for your application registration
    Choose Personal Microsoft accounts only
    Be sure to choose Single-page application (SPA)
    Enter the Redirect URI for OAuth; it is your URL + oauth-result/onedrive.html
    Click Register.
    Congratulations: you now registered your application!


  4. You now have to add another permission. Choose API Permissions. By default the only permission is User.Read

  5. Choose Add a permission

  6. From the blade that opens choose Microsoft Graph and then Delegated Permissions.

  7. From Files select Files.ReadWrite
    Click Add permission
    Now the permission is added and visible.

Login in your OneDrive and place your KeePass database (in casu: test.kdbx) in the Documents folder.

We now have to configure Keeweb. Add a config.json to your Keeweb directory on the file server.

{
    "settings": {
        ...
        "onedriveClientId": "<<Application (client) ID>>",
        "onedriveTenantId": "consumers"       
    },
    "files": 
    [
      {
        "storage": "onedrive",
        "name": "Test Onedrive",
        "path": "/drive/root:/Documents/test.kdbx"
      }
    ],
    "showOnlyFilesFromConfig": false
}

Use the Application (client) ID from Azure as “OneDriveClientID“. For “OneDriveTenantID” use “consumers“.

In the files section you define the database file. Be sure to start the “path” with /drive/root:.

Refer to the Keeweb configuration page and the Keeweb github for an explanation of the settings.

Dropbox

Prerequiste:

  • You need a Dropbox account. The free account is sufficient.

Following are the steps to take:

First we have to register Keeweb as application with the Identity Provider of Dropbox.

  1. Go to the App Console

  2. Press Create app

  3. Select the values shown above and press Create app. We choose App Folder, to give Keeweb only access to a specific folder. Note that the name must be unique within Dropbox. So obvious names like Keeweb or KeewebTest are already taken. In this example we name our App KeewebTest2023.
    We have now registered the Keeweb app. The App key and App secret we need to fill in in config.json.

  4. Now we need to register the OAuth redirection URL. The URL consists of your.domain + oauth-result/dropbox.html. Fill it in and press Add

  5. Then we need to set the permissions. Select the Permissions tab. Set the permissions as indicated and press Submit.

    Now we are done here.

We need to adapt our config.json.

{
    "settings": {
        ...
        "dropboxAppKey": "<<user>>",
        "dropboxSecret": "<<secret>>",
        "dropboxFolder": "/"          
    },
    "files": 
    [
      {
        "storage": "dropbox",
        "name": "Test Dropbox",
        "path": "test.kdbx"
      }
    ],
    "showOnlyFilesFromConfig": false
}

In dropboxAppKey and dropboxSecret we fill in the App key and App secret from the app registration. A bit surprising is that for the dropboxFolder we need to fill in / and not /App/KeewebTest2023!

Add your KeePass database file test.kdbx to the files section as shown.

Now comes a very special trick. Open your KeePass website. After selecting your database Test Dropbox and entering your master password in Keeweb, you are redirected to the Dropbox Identity Provider and you need to log in.

Then you need to consent that the App will access your files

After this procedure, the opening of the database fails since we did not put the KeePass database on Dropbox yet. However, the directory /Apps/KeewebTest2023 has been created by Dropbox with all the proper rights and stuff!
Now we need to place our KeePass database file in this directory. Note that in the config.json this path /Apps/KeewebTest2023 is not mentioned!

Finally, you can access your KeePass database by selecting your KeePass database again and entering the master key. Tadaaaaa!