Encryption Plugin for Firebird 3.0
IBPhoenix have developed an encyption plugin for Firebird 3.0 that is compatible with AES128 or AES256, AES128 is considered to be a "business-grade security", whilst AES256 is "military". Note that AES256 has a performance cost v's AES128.
The plugin is available for Windows (32/64bit), Linux (32/64bit) and MacOSX (32/64bit) currently. The plugin is currently in use at a number of sites and shows no problems with performance or reliability. However if you would like to test it, please contact us directly and an appropriate download will be made available.
To use this plugin you need to have CPU that supports the SSE2 instruction set. The AES instruction set is desirable, but optional. For Linux also make sure that the libtommath libraries are installed. Also GLIBC_2.14+ is required.
Unzip the encryption libraries and conf files into $(root_dir)/plugins
create a keyfile somewhere e.g:
C:\MyKey.txt or on Posix /opt/firebird/MyKey.txt
Now insert your key into it e.g. TestKey
Then in the file plugins KeyFile.conf you can set a server wide key using the parameter:
KeyFile = C:\MyKey.txt or /opt/firebird/MyKey.txt.
Alternatively entries for database dedicated key files can be specified for each database individually using the format <key name> = <key file>. For example suppose you have two databases testa.fdb and testb.fdb that you want to encrypt and decrypt with a separate key. Make a name up for each key and point each key name to the file holding the relevant key:
Key4TestA = C:\Key4TestA.jpg Key4TestB = C:\Key4TestB.txt
If dedicated key names are configured the name of the key must be supplied in the optional KEY parameter of the encrypt and decrypt statements.
Another alternative is to configure the keyfile so the plugin will send a request to the user application for the file path (Keyfile = ?).
You also need to set the following in Keyfile conf when using a known key file, set DisableCallback to "true". (Make sure you remove the # signs when setting conf parameters):
DisableCallback = true
Perhaps the securest and simplest way to manage this is to put the key file onto a secure USB stick inserted into database server)
In databases.conf (or firebird.conf) set the following parameter for the appropriate database:
KeyHolderPlugin = KeyFile
Restart the Firebird Server.
isql> connect 'C:\test\firebird\test.fdb' user 'SYSDBA' password 'whatever'; isql> alter database encrypt with AES128; isql> commit;
or on Posix:
isql>connect 'localhost:/opt/firebird/test.fdb' user 'SYSDBA' password 'whatever'; isql>alter database encrypt with AES128; isql>commit;
If using individual keys:
isql> connect 'C:\test\firebird\test.fdb' user 'SYSDBA' password 'whatever'; isql> alter database encrypt with AES128 key TestKey; isql> commit;
isql>connect 'localhost:/opt/firebird/test.fdb' user 'SYSDBA' password 'whatever'; isql>alter database encrypt with AES128 key TestKey; isql>commit;
Use AES256 if you are using the AE256 key.
If the encryption library fails to load then this error will be seen:
Statement failed, SQLSTATE = HY024 unsuccessful metadata update -ALTER DATABASE failed -Crypt plugin AES256/128 failed to load
There are three ways to verify encryption.
Via isql show db:
SHOW DB; Database: test Owner: SYSDBA [...] Database encrypted, crypt thread not complete
By querying the monitoring tables:
select MON$CRYPT_PAGE * 100 / MON$PAGES as ENCRYPTED_PAGES from mon$database; ENCRYPTED_PAGES ===================== 0
If ZERO is returned then encryption has completed. Otherwise the value represents the percentage of total pages encrypted.
Or by using gstat (you can use shell to run gstat from isql), With the default -h option the Attributes field and the Key Hash fields will indicate encryption.
Or you can use:
/opt/firebird3/bin/gstat -e test.fdb Database "/data_store/ssd/ods120/test.fdb" Database header page information: Flags 0 Generation 2990307 System Change Number 0 Page size 16384 ODS version 12.0 [...] Creation date May 24, 2016 12:18:12 Attributes force write, encrypted, plugin AES128 Variable header data: Key hash: X2ZorqRShODg1mhSg5yQhpFxtjk= Sweep interval: 0 *END* Data pages: total 159004, encrypted 159004, non-crypted 0 Index pages: total 16409, encrypted 16409, non-crypted 0 Blob pages: total 0, encrypted 0, non-crypted 0
Should show that the database has been encrypted
To decrypt use:
isql> alter database decrypt;
isql> alter database decrypt key TestKey;
You can also use the fb_info_crypt_state item for the isc_database_info() API call to check the encryption status of the database too.
Rather than providing the decryption key in a file, it is possible to provide the decryption key directly within your application using the relevant Firebird API calls. To do this, change the declaration of KeyHolderPlugin in databases.conf (or Firebird.conf) from KeyFile to Callback. This will allow you to provide the crypt key directly from the application.
To check if the configuration is correct, you can look at the data, received by the application callback in the first two parameters. The data will be "AES128.<something>" for old versions of plugin and "AES256/128" for version 1.2+ If you can see that, then the configuration is correct and the application can send the crypt key. If you still see "KeyFile.<something>", the configured key holder is still KeyFile and that is a file name, not the key itself.
Currently we have examples for Delphi, C++ and .NET.
This code works using Delphi XE6 or XE7, However there does seem to be a problem with earlier versions of Delphi e.g. Delphi XE3.
The Firebird referred to in the "uses" section is the Firebird.pas that can be found in the include Firebird directory of the Firebird installation.
C/C++ Code C example of how to use the encryption plugin and pass the key from a client application.
Or alternatively you can use the following new function in ibase.h:
/*******************************************/ /* Set callback for database crypt plugins */ /*******************************************/ ISC_STATUS ISC_EXPORT fb_database_crypt_callback(ISC_STATUS*, FB_NAMESPACE_USE(Firebird, ICryptKeyCallback*)); #ifdef __cplusplus } /* extern "C" */ #endif
The second parameter is declared as void*, because of the use of namespace Firebird (where the interfaces live) breaks the old-style ibase.h. This can cause problems when passing some implementations of ICallback due to incorrect type casts.
To avoid it one should first cast the pointer to the implementation of ICallback* like this:
CryptKey key; ICryptKeyCallback* cb = &key; fb_database_crypt_callback(status, cb);
Doing the following directly:
CryptKey key; fb_database_crypt_callback(status, &key);
may cause a segmentation fault.
Example of a Visual C++ Class that uses fb_database_crypt_callback.
.NET needs the ADO.NET provider 188.8.131.52, and then you can use this code.
In the configuration files Callback.conf and KeyFile.conf it is now possible to use the parameter ShareKey, where a key received from a client application will be shared between connections in SuperServer mode. When set to false (default is true) it will then require a key for each database attachment:
On purchase of an appropriate server license a download of the software will be made available. A server license costs $250.00 and will allow you to encrypt multiple databases on that server. Should you wish to use the encryption plugin with an embedded application or for deployment to multiple servers you can purchase an unlimited use license for $2499.00.