Sailfish Crypto
API DocumentationSailfish OS Crypto Library
The Sailfish OS Crypto Library provides applications with API to access the cryptography functionality offered by the system service daemon as part of the Sailfish OS Secrets and Crypto Framework.
Note: The Sailfish OS Secrets and Crypto Framework is still in active development and is subject to change. Normal 3rd party API backward compatibility promises don't hold. Follow Sailfish OS Forum release notes to get notified of API changes.
Sailfish OS Crypto Architecture
Applications running on highly-connected devices require the capability to perform advanced cryptographic operations, in order to protect the user's data, authenticate with remote services, verify the authenticity of other connected devices, and communicate securely. The keys and certificates which are used to perform such operations also need to be stored securely on the device, in order to prevent malicious third-party applications from accessing those keys.
In order to provide this capability, Sailfish OS includes a system service (extensible via vendor-specific plugins) which offers both secure storage of keys and the ability to perform cryptographic operations on behalf of client applications. Client applications access this service via the Sailfish OS Crypto Library, which provides an asynchronous API for performing a variety of operations (and hides the IPC used as an internal implementation detail).
Applications using the Sailfish OS Secrets and Crypto Framework delegate cryptographic operations to the system service, and the framework has been designed to ensure that when used appropriately, secret key data need never enter the process address space of the application. Furthermore, if the cryptographic service provider plugin to the framework is backed by secure hardware, Trusted Execution Environment application, or Trusted Platform Module, then secret key data need never enter the normal "rich" execution environment.
Using the Sailfish OS Crypto Library
As described in the Sailfish OS Secrets and Crypto Framework overview documentation, client applications can use the Sailfish OS Crypto Library in order to make use of the cryptographic services provided by the Sailfish OS Secrets and Crypto Framework.
This library provides client applications written in C++ (with Qt) with API to make use of the cryptographic services provided by the Sailfish OS Secrets and Crypto Framework.
To make use of this library, applications should depend on the "sailfishcrypto.pc" pkgconfig file.
e.g. in a qmake-based project:
CONFIG += link_pkgconfig PKGCONFIG += sailfishcrypto
Client API
The client API consists of a variety of C++ classes which represent the inputs to cryptographic operations (including public, private and secret keys), the result of a cryptographic operation (that is, whether it succeeded or failed, along with some information about the reason for the failure), and one class which provides an interface to the remote service.
- Sailfish::Crypto::Key represents a (possibly partial or reference) cryptographic key
- Sailfish::Crypto::Key::Identifier consists of a key name and optionally a collection name
- Sailfish::Crypto::Result represents the result (but not the output) of a cryptographic operation
- Sailfish::Crypto::CryptoManager provides an interface to the system cryptography service
In order to perform a cryptographic operation, clients must request that the system service perform the operation on their behalf, and either return the result to them, or store it securely. There are a variety of request-specific classes which provide this functionality:
- Sailfish::Crypto::PluginInfoRequest to retrieve information about crypto plugins
- Sailfish::Crypto::SeedRandomDataGeneratorRequest to seed a crypto plugin's random number generator
- Sailfish::Crypto::GenerateRandomDataRequest to generate random data
- Sailfish::Crypto::GenerateInitializationVectorRequest to generate an initialization vector for use in encryption or decryption
- Sailfish::Crypto::GenerateKeyRequest to generate a Key
- Sailfish::Crypto::GenerateStoredKeyRequest to generate a securely-stored Key
- Sailfish::Crypto::ImportKeyRequest to import a Key from a data file
- Sailfish::Crypto::ImportStoredKeyRequest to import a Key from a data file and store it securely
- Sailfish::Crypto::StoredKeyRequest to retrieve a securely-stored Key
- Sailfish::Crypto::StoredKeyIdentifiersRequest to retrieve the identifiers of securely-stored Keys
- Sailfish::Crypto::DeleteStoredKeyRequest to delete a securely-stored Key
- Sailfish::Crypto::EncryptRequest to encrypt data with a given Key
- Sailfish::Crypto::DecryptRequest to decrypt data with a given Key
- Sailfish::Crypto::CalculateDigestRequest to calculate a digest (non-keyed hash) of some data
- Sailfish::Crypto::SignRequest to generate a signature for some data with a given Key
- Sailfish::Crypto::VerifyRequest to verify if a signature was generated with a given Key
- Sailfish::Crypto::CipherRequest to start a cipher session with which to encrypt, decrypt, sign or verify a stream of data
Usage Examples
The examples directory in the source repository contains a variety of examples of usage of the Sailfish OS Crypto Library as well as the Sailfish OS Secrets Library. Please see those for complete, working examples.
Some snippets showing commonly-required functionality are included below.
Generating a securely-stored symmetric cipher key
This snippet shows how to generate a symmetric cipher key which will be stored securely by the Sailfish OS Secrets and Crypto Framework. It assumes that a secure storage collection has previously been created, in which to store the key. Please see the Sailfish OS Secrets Library documentation for information about how to create such a collection.
First, the client defines the algorithm, supported block modes, supported padding schemes, and supported operations in a template key. That template key is given an identifier which includes the name of the key and the name of the secure storage collection in which it should be stored, and is then set as a parameter in the GenerateStoredKeyRequest instance, which, when started, results in an IPC call to the secure Sailfish OS Secrets and Crypto Framework system service.
The Sailfish OS Secrets and Crypto Framework system service will then delegate the operation to the specified crypto plugin, which in turn will generate a full symmetric key based upon the given template, and store it securely. A reference key (that is, a key containing a valid identifier and metadata, but no secret key data) will be returned to the client application.
Note that these operations are all asynchronous, however in the snippet we force the operation to be synchronous by calling the waitForFinished()
method of the request object. In practice, the client application should instead listen to the signals which notify when the operation is complete.
// Set the key template metadata. Sailfish::Crypto::Key keyTemplate, symmetricKeyReference; keyTemplate.setAlgorithm(Sailfish::Crypto::CryptoManager::AlgorithmAes); keyTemplate.setSize(256); keyTemplate.setOrigin(Sailfish::Crypto::Key::OriginDevice); keyTemplate.setOperations(Sailfish::Crypto::CryptoManager::OperationEncrypt |Sailfish::Crypto::CryptoManager::OperationDecrypt); // Set the identifier for the key. // This assumes the existence of an "ExampleCollection" secure storage // collection, in which the key will be stored. // See Sailfish::Secrets::CreateCollectionRequest. keyTemplate.setIdentifier( Sailfish::Crypto::Key::Identifier( QStringLiteral("ExampleKey"), QStringLiteral("ExampleCollection"), Sailfish::Crypto::CryptoManager::DefaultCryptoStoragePluginName)); // Ask the system service to generate and store the key securely. Sailfish::Crypto::CryptoManager cm; Sailfish::Crypto::GenerateStoredKeyRequest generateRequest; generateRequest.setManager(&cm); generateRequest.setKeyTemplate(keyTemplate); generateRequest.setCryptoPluginName(Sailfish::Crypto::CryptoManager::DefaultCryptoStoragePluginName); generateRequest.startRequest(); generateRequest.waitForFinished(); if (generateRequest.result().code() == Sailfish::Crypto::Result::Failed) { qWarning() << "Unable to generate and store symmetric key:" << generateRequest.result().errorMessage(); } else { symmetricKeyReference = generateRequest.generatedKeyReference(); }
Encrypting data with a symmetric key
After generating a symmetric key, that key may be used to encrypt data. Note that the key may be either a key reference (that is, a key which contains only metadata and a valid identifier, which references a full key stored in secure storage) or a full key (that is, a key which contains secret key data).
In this example, we use the reference key which was returned to the application in the previous snippet.
QByteArray iv, ciphertext, plaintext = "Example plaintext data"; GenerateInitializationVectorRequest ivRequest; ivRequest.setManager(&cm); ivRequest.setAlgorithm(symmetricKeyReference.algorithm()); ivRequest.setKeySize(symmetricKeyReference.size()); ivRequest.setBlockMode(Sailfish::Crypto::CryptoManager::BlockModeCbc); ivRequest.setCryptoPluginName(Sailfish::Crypto::CryptoManager::DefaultCryptoStoragePluginName); ivRequest.startRequest(); ivRequest.waitForFinished(); if (ivRequest.result().code() == Sailfish::Crypto::Result::Failed) { qWarning() << "Failed to generate initialization vector:" << ivRequest.result().errorMessage(); } else { iv = ivRequest.generatedInitializationVector(); } EncryptRequest encryptRequest; encryptRequest.setManager(&cm); encryptRequest.setData(plaintext); encryptRequest.setInitializationVector(iv); encryptRequest.setKey(symmetricKeyReference); encryptRequest.setBlockMode(Sailfish::Crypto::CryptoManager::BlockModeCbc); encryptRequest.setPadding(Sailfish::Crypto::CryptoManager::EncryptionPaddingNone); encryptRequest.setCryptoPluginName(Sailfish::Crypto::CryptoManager::DefaultCryptoStoragePluginName); encryptRequest.startRequest(); encryptRequest.waitForFinished(); if (encryptRequest.result().code() == Sailfish::Crypto::Result::Failed) { qWarning() << "Failed to encrypt:" << encryptRequest.result().errorMessage(); } else { ciphertext = encryptRequest.ciphertext(); }
Decrypting data with a symmetric key
A symmetric key may also be used to decrypt data. In the following snippet, the client asks the system service to decrypt the ciphertext with the same key reference, to produce decrypted data.
DecryptRequest decryptRequest; decryptRequest.setManager(&cm); decryptRequest.setData(ciphertext); decryptRequest.setInitializationVector(iv); decryptRequest.setKey(symmetricKeyReference); decryptRequest.setBlockMode(Sailfish::Crypto::CryptoManager::BlockModeCbc); decryptRequest.setPadding(Sailfish::Crypto::CryptoManager::EncryptionPaddingNone); decryptRequest.setCryptoPluginName(Sailfish::Crypto::CryptoManager::DefaultCryptoStoragePluginName); decryptRequest.startRequest(); decryptRequest.waitForFinished(); if (decryptRequest.result().code() == Sailfish::Crypto::Result::Failed) { qWarning() << "Failed to decrypt ciphertext:" << decryptRequest.result().errorMessage(); } else { QByteArray decrypted = decryptRequest.plaintext(); qDebug() << "Decrypted:" << decrypted; }
Extending the Sailfish OS Secrets and Crypto Framework with Crypto Plugins
The Sailfish OS Crypto Library also provides a plugin base-class which may be extended by device vendors or trusted partners to allow them to build plugins to extend the Sailfish OS Secrets and Crypto Framework with additional cryptography functionality (for example, supporting different algorithms or block modes, or performing the operations via a Trusted Execution Environment application rather than in-process in the rich application process).
The Sailfish::Crypto::CryptoPlugin class should be extended in order to achieve this, and the resulting plugin should be installed into the /usr/lib/Sailfish/Crypto/
directory.
Note that if you wish to provide secure key storage as well as cryptographic services to clients, you also need to extend Sailfish::Secrets::EncryptedStoragePlugin
. For more information about that topic, please see the documentation about the Sailfish OS Secrets library.
A variety of crypto plugins are shipped by default with the framework, and these are documented at the page about Default Crypto Plugins for the Sailfish OS Secrets and Crypto Framework.
One of these in particular is useful to use as an example or basic template, and that is the ExampleUsbTokenPlugin which can be found in the source tree.