Skip to content

KeePassOTP storage approaches

Rookiestyle edited this page Dec 26, 2021 · 6 revisions

KeePassOTP can be configured to store OTP data either within the respective entry or in a separate database.

If stored within a separate database, this database

  • can be unlocked automatically when the main database is opened
  • can be unlocked upon first access
  • will always be unlocked during synchronisation of the main database to avoid data loss

These settings are database-specific.
You can switch between those two modes anytime.

OTP storage within the respective entry

If you set up OTP, all required information is stored in up to two string fields within the respective entry.
Wiki page KeePassOTP fields describes these fields more in detail.

Pro:

  • Exporting the database will export OTP data as well
  • Database synchronization will synchronize OTP data as well
  • Ports like KeePass2Android can be used to calculate OTP as they can read these fields

Con:

OTP storage in a separate database

If you set up OTP, all required information is stored in up to two string fields in a new entry in a separate database - the OTP-DB.
Wiki page KeePassOTP fields describes these fields more in detail.

In addition, these entries will contain the main entries' UUID to be able to match the entries in the two databases.
The UUID uniquely identifies an entry and is the ideal way to match corresponding entries while other attributes like title or username might change or be ambiguous.

This OTP-DB is stored in the main database' CustomData entry:

  • Field name: KeePassOTP.DB
  • Format: standard KeePass database
  • Masterkey: All options that are available for the main database can be used: password, keyfile, windows user account, key provider plugins
  • Database settings: Can be changed anytime: Encryption algorithm, key transformations, ...

When the main database is opened and the OTP-DB needs to be accessed

  • An empty database object is created in memory (it will never be safed to disk)
  • The OTP-DB's masterkey is requested from the user
  • The built-in sync functionality is used to synchronize the stored database (KeePassOTP.DB) with the empty database
  • Synchronizing relies on the masterkeys being identical
  • As the database object is empty, synchronizing will simply copy all entries from the attachment into the database object

During a synchronization of the main database

  • The OTP-DB is unlocked if required (see above)
  • The built-in sync functionality is used to synchronize the stored database (KeePassOTP.DB) with the OTP-DB stored in the synchronized database
  • Synchronizing relies on the masterkeys being identical

As soon as the main database is locked/closed, the OTP-DB is closed as well.

This does not require any additional plugins or triggers.

Pro:

  • Database synchronization will synchronize OTP data as well
  • OTP data is secured by an additional masterkey - hopefully it is a strong masterkey and different from your main database' masterkey
  • A person with access to your database cannot read OTP secrets

Con:

  • Exporting the database will not export OTP data as well, this needs to be done manually by using the easily accessible options
  • Ports like KeePass2Android canot be used to calculate OTP as they are not aware of this 2nd database

Technical details

Following data is stored in the main database's custom data.

Field Value
KeePassOTP.DB encrypted KeePass database as base64-encoded string (only if KeePassOTP.UseDBForPTPSeeds = true)
KeePassOTP.UseDBForPTPSeeds true | false - use OTP database or use otp string within the entry in the main database
KeePassOTP.PreloadOTP true | false - Unlock OTP database when main database is unlocked
KeePassOTP.KeySources key sources used to build the masterkey, serialized KeePass.App.Configuration.AceKeyAssoc

This allows synchronization of the OTP database as part of the main database - KeePassOTP takes care of that.
Obviously the OTP database should have a different masterkey than the main database. This is not enforced by KeePassOTP.

Main database entries are known to have OTP defined if the entrie's plugin data (tab: Properties) contain a field KeePassOTP.DB with value true. The mapped entry in the OTP database is identified by comparing the main database's entry's UUID with string field Entry UUID in the OTP database entries.

In addition to these fields, entry specific data is stored as well, cf. KeePassOTP fields