public final class DatabaseConfig
- Object
- DatabaseConfig
Describes how a database should be opened, and in particular how it is keyed.
Pass an instance to Database#openOrCreate(java.lang.String, com.codename1.db.DatabaseConfig).
Opening without a config, through Database#openOrCreate(java.lang.String), is
always plaintext and always will be – there is no implicit upgrade.
Security
A passphrase written into your source code is not a secret. String literals
are recoverable from a shipped .ipa or .apk in minutes, so a constant passphrase
buys you nothing against anyone who has the file. This is the mistake that gets
made most often, so it is worth being blunt about it: if your application cannot
ask a human for a passphrase, use #managed() instead. A random key held in the
platform key store is strictly better than a constant compiled into the binary.
Encryption here protects data at rest and nothing else. It does not defend against a rooted or jailbroken device, a debugger attached to the running process, or a memory dump: while the database is open the key is in memory.
Choosing a mode
// A human supplies the secret. Nothing is stored on the device.
DatabaseConfig.passphrase(passwordField.getText());
// No secret to manage. A random key is generated once and kept in the
// platform key store. Best default when there is nobody to prompt.
DatabaseConfig.managed();
// The application already has 32 bytes of key material of its own.
DatabaseConfig.rawKey(keyBytes);
// Explicitly plaintext.
DatabaseConfig.plain();
On-disk format
Every platform that supports encryption reads and writes the same format, so a
database created on one device can be opened on another and in the simulator.
See the com.codename1.db package documentation for the pinned parameters.
Fields
public static final int KEY_NONE = 0 | No encryption. |
public static final int KEY_PASSPHRASE = 1 | The key is derived from an application supplied passphrase. |
public static final int KEY_MANAGED = 2 | The key is random, generated once, and held in the platform key store. |
public static final int KEY_RAW = 3 | The key is 32 raw bytes supplied by the application. |
public static final int KEY_VAULT = 4 | The key is derived from an unlocked Vault. |
Methods
public static DatabaseConfig plain() | Returns a config that opens the database unencrypted. |
public static DatabaseConfig passphrase(String passphrase) | Returns a config keyed from the supplied passphrase. |
public static DatabaseConfig managed() | Returns a config keyed by a random key held in the platform key store, using the database name as the key alias. |
public static DatabaseConfig managed(String keyAlias) | Returns a config keyed by a random key held in the platform key store under an explicit alias. |
public static DatabaseConfig rawKey(byte[] key) | Returns a config keyed directly by 32 raw bytes, bypassing key derivation. |
public static DatabaseConfig vault(Vault vault, String alias) | Keys the database from an unlocked vault. |
public static DatabaseConfig vault(Vault vault, String alias, int keyVersion) | Opens a vault-keyed database at a specific current or retired key version. |
public int getKeyMode() | Returns the key mode, one of #KEY_NONE, #KEY_PASSPHRASE, #KEY_MANAGED, #KEY_RAW or #KEY_VAULT. |
public boolean isEncrypted() | Returns whether this config asks for an encrypted database. |
public String getKeyAlias() | Returns the explicit managed key alias, or null when the database name is used as the alias. |
public String getCipherProfile() | Returns the cipher profile name that describes the on-disk format. |
public boolean isKeyHardwareBacked() | Returns whether keys for this config are protected by dedicated key storage hardware on the current platform. |
public void wipe() | Clears the key material held by this config. |
public String resolveKeyMaterial(String databaseName)
throws IOException | Produces the key literal handed to the underlying engine. |
public ProtectionReport effectiveKeyProtection() | What actually protects this database’s key on this device. |
Inherited methods
Field details
KEY_NONE
public static final int KEY_NONE = 0KEY_PASSPHRASE
public static final int KEY_PASSPHRASE = 1KEY_MANAGED
public static final int KEY_MANAGED = 2KEY_RAW
public static final int KEY_RAW = 3KEY_VAULT
public static final int KEY_VAULT = 4The key is derived from an unlocked Vault.
Different from #KEY_MANAGED in where the protection comes from. A managed key is held by
the platform key store and is available whenever the application runs; a vault key exists
only while the user has unlocked the vault, which is what makes it usable in a browser –
there is no key store in a page, and a key that is always available there is a key sitting
in the open.
Method details
plain
public static DatabaseConfig plain()Returns a config that opens the database unencrypted.
This is identical to calling Database#openOrCreate(java.lang.String) and
exists so that code choosing between modes at runtime has something to
return for the plaintext case.
Returns
passphrase
public static DatabaseConfig passphrase(String passphrase)Returns a config keyed from the supplied passphrase.
The passphrase is stretched into a key by the cipher’s key derivation function, so a weak passphrase yields a weak database. Nothing is stored on the device: losing the passphrase means losing the data.
Parameters
passphraseString- the secret, which must not be null or empty, and must not contain the character with code point zero
Returns
Throws
IllegalArgumentException- if the passphrase is null, empty, or contains the character with code point zero
managed
public static DatabaseConfig managed()Returns a config keyed by a random key held in the platform key store, using the database name as the key alias.
The first time a database is opened this way a fresh random key is generated and stored. Subsequent opens retrieve the same key. The application never sees or handles the key.
Durability
The key lives and dies with the platform key store entry. Uninstalling the
application, wiping the device, or – on Android – restoring a backup onto a
different device leaves the database permanently unreadable, because
Android key store keys cannot be exported. iOS keychain entries do survive
an encrypted backup and restore. If the data must outlive the device, use
#passphrase(java.lang.String) with a secret the user or your server holds.
Returns
managed
public static DatabaseConfig managed(String keyAlias)Returns a config keyed by a random key held in the platform key store under an explicit alias.
Use this when several databases should share one key, or when the database name may change but the key should not.
Parameters
keyAliasString- the key store alias, which must not be null or empty
Returns
Throws
IllegalArgumentException- if the alias is null or empty
See also
rawKey
public static DatabaseConfig rawKey(byte[] key)Returns a config keyed directly by 32 raw bytes, bypassing key derivation.
Use this when the application already derives key material by its own means, for instance from a server-issued secret. Because no key derivation function is applied, the bytes must already be uniformly random – do not pass a hashed password here and expect passphrase-grade protection.
Parameters
keybyte[]- exactly 32 bytes of key material
Returns
Throws
IllegalArgumentException- if the array is null or is not exactly 32 bytes
vault
public static DatabaseConfig vault(Vault vault, String alias)Keys the database from an unlocked vault.
The key is derived from the vault’s data key – see
Vault.databaseKey(String), including its honest account of
what handing raw bytes to a database engine costs. The vault must be unlocked when the
database is opened; it need not stay unlocked afterwards, because the engine has the key
by then, and locking the vault does not close an open connection.
What this buys over #managed()
In a browser, everything. managed() keeps its key wherever the port’s secure storage is,
which in a page is origin-private storage – now encrypted under a non-extractable
CryptoKey, and still readable by anything running in the origin at any time, because
nothing gates it. A vault key does not exist until the user unlocks, so a page loaded and
left alone has no database key in it at all.
On Android and iOS the two are closer: a managed key already sits in the OS key store. The vault still adds the user’s password to the chain, and adds cross-device portability, which a key generated per device does not have.
Rotation
Vault.rotateDataKey changes this key. A database opened
under the old one has to be rekeyed in the same operation or it can no longer be opened;
there is no automatic rekey, because an interrupted one leaves a database encrypted under
neither key and that is not a thing to do behind a caller’s back. An imported rotation has
the same effect. Use vault(com.codename1.security.vault.Vault,String,int) with the
database’s recorded key version to reopen an older file before rekeying it.
Parameters
vaultVault- an unlocked vault
aliasString- the key alias within the vault, normally the database name
Returns
vault
public static DatabaseConfig vault(Vault vault, String alias, int keyVersion)Opens a vault-keyed database at a specific current or retired key version.
Store the version with the database when creating or rekeying it. After importing a remote
rotation, this config can still open the existing file; Database.changeKey can then move
it to a config using the newer version. No automatic rekey or version guessing is performed.
vault: the unlocked vault that owns the databasealias: the original database key aliaskeyVersion: the positive version used to encrypt the existing file
getKeyMode
public int getKeyMode()#KEY_NONE, #KEY_PASSPHRASE, #KEY_MANAGED,
#KEY_RAW or #KEY_VAULT.Returns
isEncrypted
public boolean isEncrypted()Returns
#KEY_NONEgetKeyAlias
public String getKeyAlias()Returns
getCipherProfile
public String getCipherProfile()Returns the cipher profile name that describes the on-disk format.
Only one profile is currently defined. The accessor exists so that a future profile can be introduced without changing the shape of this class.
Returns
isKeyHardwareBacked
public boolean isKeyHardwareBacked()Returns whether keys for this config are protected by dedicated key storage hardware on the current platform.
This is false for #passphrase(java.lang.String) and #rawKey(byte[]),
because the application, not the platform, holds that key material. For
#managed() it reflects the platform: true where a hardware backed key
store is available, and false in the simulator, where the key is
protected only by a software derived key in the desktop user profile.
Applications with a hard requirement on hardware backing should check this and refuse to store sensitive data when it returns false.
Returns
wipe
public void wipe()Clears the key material held by this config.
Call this once the database has been opened. The passphrase and raw key buffers are overwritten with zeroes.
Note the honest limitation: the value actually handed to the database engine
is a String, because every supported engine keys from one, and Java strings
are immutable and cannot be wiped. This method reduces the window, it does
not eliminate it.
resolveKeyMaterial
public String resolveKeyMaterial(String databaseName)
throws IOExceptionProduces the key literal handed to the underlying engine.
This exists for the platform implementations; applications have no reason to call it.
Passphrases are returned verbatim. Raw and managed keys are rendered as the literal x'
followed by 64 hexadecimal characters and a closing quote, which is the one form every
supported engine interprets identically as a raw key with no key derivation applied.
For a managed key this is the call that generates and stores the key on first use, so it can fail even though the config itself was built successfully.
Parameters
databaseNameString- used as the key store alias when no explicit alias was set
Returns
Throws
IOException- if a managed key could not be produced or stored
effectiveKeyProtection
public ProtectionReport effectiveKeyProtection()What actually protects this database’s key on this device.
#isKeyHardwareBacked() answers one bit of this and has to answer false wherever it
cannot verify, which reads the same as “definitely not”. This reports each protection
separately and distinguishes “no” from “cannot say” – see
ProtectionReport.