Linphone file encryption

Last modified by Johan Pascal on 2020/06/26 15:26

Bctoolbox Virtual File System

Bctoolbox provides a Virtual File System mechanism. A standard C API allows to open/close/read/write files. See vfs.h for details on the API. At file opening, user must select a VFS implementation to use. Bctoolbox currently provides two implementation, the standard one and the encrypted one.

Any implementation can be set as the default one.

Standard VFS

Direct access to the file system function in a portable way

Encrypted VFS

Add an encryption layer on top of the standard VFS. The encryption itself is a module which can be selected by user on a file basis.

The Encrypted VFS adds a file header holding meta-data and split the file in chunks. Each of them is encrypted separately and also holds a header with meta-data.

The encryption/decryption uses a master-key to operate on a file. The master key can be common to all files as it is not used directly. The secure storage of the master key is out of the scope of the encrypted VFS.

At file opening, a callback will request the master key(and others settings for a file creation). The callback is a class one and is thus globally set.

Encryption Modules

Plain

Choosing the plain module turns the encryption layer off. It can be useful to avoid encrypting some files (temporary files, log files, db-journal) while keeping the encrypted VFS as default.

Dummy

The dummy encryption module does not provide security and is a debugging/dev tool. DO NOT USE IT for any other purpose

AES256GCM128 Sha256

This is the default module. Data is encrypted and authenticated using AES256GCM128. File header is authenticated using HMAC-SHA256.

At file creation, a 128bits fileSalt is randomly generated and stored in the file header.

The master key requested by this module is 256bits long. It is then derived to generate:

  • a HMAC key to authenticate the file header: fileHeaderKey<32 bytes> = HKDF-SHA256Master Key, fileSalt, "EVFS file header")
  • each file chunk would use chunkKey<32 bytes> = HKDF-SHA256(Master Key, file Salt || Chunk Index, "EVFS chunk"). Chunk Index being the index of the chunk in the file.

The file header authentication using fileHeaderTag = HMAC-SHA256(fileHeaderKey, fileHeader  - excluding fileSalt and fileHeaderTag-) is performed at file opening and ensure the meta data and the file Salt have not been tempered and the master key is correct. The generated tag is compared with the one stored in the file header.

Each chunk header stores a 16bytes authentication tag and a 12 bytes IV. The encryption/authentication is performed as follow:

  • generate a random IV. This is performed at each encryption to avoid reusing a key/IV couple. A deterministic way of generating the IV could lead to key/IV reuse as an attacker could restore the file to a previous state and manages to have the system writing a different plain text thus getting access to the original one.
  • encrypt using cipher, tag = AES256GCM128(chunkKey, IV, cipher) - no associated data provided
  • store tag, IV and cipher in the chunk

Plain file migration

Encrypted VFS is able to acces plain files transparently. If the file is accessed with write access and an encryption module other than plain is selected, the file will be overwritten with its encrypted version. Read-only access leave the file in plain state.

Enabling file encryption in linphone

Setting the encryption master key

Call linphone_factory_set_vfs_encryption after the linphone factory creation and before the first linphone core creation to be able to access the encrypted linphone_rc.

Calling this function will set the encrypted VFS callback, store the encryption master key in the factory and set the encrypted VFS as default (including for sqlite3 access).

C++ sources can modify the encrypted VFS callback  by calling directly its set function, this allows more options like having some file encrypted and not others based on their name.

Every file access (including the sqlite3 db access) performed by the linphone library uses the default bctoolbox VFS, they would thus all be encrypted. The only exceptions are the log files which directly use the C API to access the file system and are thus not impacted.

File transfer access to plain content

File downloaded from file transfer message are also encrypted on the disk if the encryption is enabled.

The application can request the encryption status using the isEncrypted method on FileContent object (linphone_content_is_file_encrypted for C API). If the file is encrypted, the application can request a plain copy of the file by calling the getPlainFilePath on the FileContent object (linphone_content_get_plain_file_path for C API). The application is then responsible for this plain file and must delete it when done.