Sailfish Secrets
API DocumentationDefault Secrets Plugins for the Sailfish OS Secrets and Crypto Framework
A number of plugins have been written for the framework which provide a variety of functionality for clients to use. Most clients should use the platform default plugins when writing their applications, as these will provide the most consistent and secure experience.
Device vendors and trusted partners may wish to provide their own plugins, and some applications may wish to specifically use those plugins.
Default Secrets Plugins
Currently, there are several Sailfish OS Secrets plugins shipped by default:
- org.sailfishos.secrets.plugin.encryption.openssl
- org.sailfishos.secrets.plugin.storage.sqlite
- org.sailfishos.secrets.plugin.encryptedstorage.sqlcipher
- org.sailfishos.secrets.plugin.authentication.passwordagent
- org.sailfishos.secrets.plugin.authentication.inapp
The first plugin is used internally to encrypt the data in a secret when that secret is either standalone or stored in a collection in unencrypted storage. This plugin uses the OpenSSL library to perform the encryption.
The second plugin provides unencrypted storage for collections of secrets.
The third plugin provides (block-level) encrypted storage for collections of secrets (using the popular SQLCipher as its database storage backend). When using this plugin, every collection is stored in its own database. Note: this plugin is also a Sailfish OS Crypto plugin.
The fourth plugin provides system-mediated authentication flows, for cases where the user need not have to trust the application with the secret data being stored.
The fifth plugin provides in-application authentication flows, for cases where the user trusts the application with the authentication data, rather than using the system-mediated authentication flows (e.g. device lock).
Note that none of these plugins use TEE/TPM or other secure-hardware to implement the cryptographic functionality.
Which Plugin Should My Application Use?
We recommend that the system default EncryptedStorage plugin be used where possible. In most cases, this will be the "org.sailfishos.secrets.plugin.encryptedstorage.sqlcipher" plugin.
In order to use the system default EncryptedStorage plugin, it should be specified for both the encryption plugin and storage plugin parameters when invoking a method via the SecretManager.
The following snippet shows an example of creating a collection of secrets in an encrypted database managed by the default encrypted storage plugin:
Sailfish::Secrets::SecretManager sm; Sailfish::Secrets::CreateCollectionRequest ccr; ccr.setManager(&sm); ccr.setCollectionName(QLatin1String("ExampleCollection")); ccr.setAccessControlMode(Sailfish::Secrets::SecretManager::OwnerOnlyMode); ccr.setCollectionLockType(Sailfish::Secrets::CreateCollectionRequest::DeviceLock); ccr.setDeviceLockUnlockSemantic(Sailfish::Secrets::SecretManager::DeviceLockKeepUnlocked); ccr.setStoragePluginName(Sailfish::Secrets::SecretManager::DefaultEncryptedStoragePluginName); ccr.setEncryptionPluginName(Sailfish::Secrets::SecretManager::DefaultEncryptedStoragePluginName); ccr.startRequest(); ccr.waitForFinished(); if (ccr.result().code() == Sailfish::Secrets::Result::Failed) { qWarning() << "Failed to create collection:" << ccr.result().errorMessage(); }
If standalone secrets are required for any reason, we recommend that the application uses the default EncryptionPlugin and default StoragePlugin. In most cases, these will be the "org.sailfishos.secrets.plugin.encryption.openssl" and "org.sailfishos.secrets.plugin.storage.sqlite" plugins respectively.
The following snippet shows an example of storing a standalone, device-lock protected secret in the default storage plugin:
// Define a standalone secret (no collection name specified in the identifier) Sailfish::Secrets::Secret standaloneSecret( Sailfish::Secrets::Secret::Identifier( QStringLiteral("StandaloneSecret"), QString(), Sailfish::Secrets::SecretManager::DefaultStoragePluginName)); standaloneSecret.setData("Example secret data"); standaloneSecret.setType(Secret::TypeBlob); standaloneSecret.setFilterData(QLatin1String("domain"), QLatin1String("sailfishos.org")); standaloneSecret.setFilterData(QLatin1String("example"), QLatin1String("true")); // Request that the secret be stored by the default storage plugin Sailfish::Secrets::SecretManager sm; Sailfish::Secrets::StoreSecretRequest ssr; ssr.setManager(&sm); ssr.setSecretStorageType(StoreSecretRequest::StandaloneDeviceLockSecret); ssr.setDeviceLockUnlockSemantic(Sailfish::Secrets::SecretManager::DeviceLockKeepUnlocked); ssr.setAccessControlMode(Sailfish::Secrets::SecretManager::OwnerOnlyMode); ssr.setEncryptionPluginName(Sailfish::Secrets::SecretManager::DefaultEncryptionPluginName); ssr.setUserInteractionMode(Sailfish::Secrets::SecretManager::SystemInteraction); ssr.setSecret(standaloneSecret); ssr.startRequest(); ssr.waitForFinished(); if (ssr.result().code() == Sailfish::Secrets::Result::Failed) { qWarning() << "Failed to store secret:" << ssr.result().errorMessage(); }
Implementing your own plugin
Please see the documentation for Sailfish::Secrets::PluginBase for more information about implementing your own custom plugin.
An example (skeleton) Encrypted Storage plugin (which also implements the CryptoPlugin
interface) may be found at: https://github.com/sailfishos/sailfish-secrets/tree/master/examples/plugins/examplecryptostorageplugin/
The Sailfish OS Secrets In-App Authentication Plugin
This plugin allows client applications written in C++ (with Qt and QML) to service authentication and input requests initiated by the daemon on behalf of the client application. This type of authentication flow is useful when the the application uses Owner-Only access control semantics, and the user trusts the application with the authentication data. It can also be utilised to avoid user interaction altogether (e.g. in the case of application data which is stored in the secrets service, where no user interaction is required).
In order to use this authentication flow, the client application may extend InteractionView, instantiate their interaction view, and register it with the SecretManager.
Alternatively, if the client application is a QML application, they may use the ApplicationInteractionView
type available from the Sailfish.Secrets
QML plugin. The client application should implement their own UI as a QML component and tell the ApplicationInteractionView
to load it, by setting the appropriate QObject property on their application, for example:
QCoreApplication::instance()->setProperty( "Sailfish::Secrets::ApplicationInteractionView::sourceUrl", QStringLiteral("CustomInteractionView.qml"));
Note: In-app authentication flows are experimental and may not be supported in the future.
Note: in general, system authentication flows should be used instead of in-process authentication flows, to ensure that the user need not trust the application with authentication data!