Page and Object Encryption

Printer-friendly version

This is informal user documentation for a new 10.1 feature that provides the ability to plug in code to encrypt and decrypt persistent objects and pages.



This project lets users provide plugin code to encrypt and decrypt persistent objects and pages.


This feature is provided for application designers with requirements for data security.

Conceptual Model

Objectivity 10.1 provides a new page and object encryption feature. With this feature, database pages can reside on disk in an encrypted representation, where each page is encrypted before being written out, and decrypted after being read into memory. The 32-byte page header is not encrypted because it contains information needed to verify the page identity and checksum before decrypting (it doesn't contain user data anyway).

Encryption and decryption is performed in the client application process, so pages are in their encrypted form while being transmitted between the client and AMS or another file server.

For object-level encryption, the representation of each object is decrypted before opening it, and encrypted after closing it. The type number in the first word of the disk format is not encrypted so that iteration can skip irrelevant objects without decrypting them, and so that the type number can be used to affect encryption or permissions. In other words, different classes can have different access policies.

Note: In this document, object refers to both persistent objects and VArrays.

An application would presumably choose to encrypt either pages or objects, but there is no prohibition against doing both. Large objects and index pages are handled as separate cases that would need to be implemented in addition to either alternative for small objects. The internal objects that implement ooMap and scalable collections are subject to encryption just like user objects.

Your plugin code must use an encryption technique in which the encrypted data is the same size as the original. This is true of block ciphers such as AES or Camellia, but is typically not the case for public key encryption.

The same plugin mechanism could also be used to implement page-level or object-level access authorization checks, either in addition to or instead of encryption.

Objectivity/DB sets an associated flag bit on each page or object that has been encrypted in order to trap attempts to read the data without having the necessary decryption code.

The encryption implementation is built as a shared library that is dynamically loaded by the Objectivity/DB plugin mechanism. The shared library must be implemented in C++, but can be used by applications using other Objectivity/DB programming interfaces.

The plugin library can be used by application programs as well as by Objectivity tools, but there could be problems with the Objectivity tools having the necessary access authority. In order to ensure the usability of basic Objectivity administration tools, an encryption plugin might choose not to encrypt anything in the system database (DB 1) or the catalog container of any database (container 1). In that case, the schema and catalog information such as database names, container names, and file names would not be encrypted and so should not contain sensitive information. This approach would allow Objectivity backup and restore tools to operate on federations containing encrypted data without decrypting any of it. (Database root pages, container root pages, map pages, and free map pages are not subject to encryption in any case.)

Even if the catalogs are not encrypted, tools that read user objects, such as oocheck , ooexportdata , and the Parallel Query Server, still need to use the encryption plugin. The encryption plugin would be used by the Lock Server only for doing recovery, and would never be relevant to AMS. (This information should be considered with regards to application deployment.)

Note: In the case of the Parallel Query Server, security authorization would depend on the user running the server, not the user running the client application. This may not be a problem because the query server only passes back OIDs (not actual data).


  • You cannot add security tags (such as for specifying access categories or encryption technique) to encrypted pages or objects.
  • You cannot control the allocation alignment of objects in order to use block ciphers with block sizes larger than 8 bytes. A byte stream cipher or DES can be used for objects, but you cannot use AES or Camellia unless the class is padded to an appropriate size. (This limitation does not apply to page-level encryption.)
  • After a decryption exception, the scan operation terminates (as opposed to having the subsequent next call skip over the problematic object or page.)
  • There is no plugin method that an iterator can call to ask whether it should visit a particular container, page, or object, so that hidden data can be skipped without an error.

Task Descriptions

To implement encryption, users need to:
  1. Define a class derived from ooEncryptionProvider.
  2. Define overrides for the relevant virtual methods of the class to perform the desired encryption and decryption. (Methods that are not overridden default to doing nothing.)
  3. Implement the plugin's entry point function createPlugin to create and return an instance of the class.
  4. Build the implementation code into a shared library.
  5. Provide a plugin specification file entry to specify the location of the library.
The Objectivity/DB kernel within an application program loads the plugin library, calls the entry point function to get an instance of the class, and registers the object for use in subsequent page and object operations. The page and object operations call back to the methods of the registered object.

Important: The code you write in your encryption and decryption routines must be reentrant.

Implement an Encryption Plugin

You define a page and object encryption plugin with C++ code in a shared library. The C++ code defines a subclass of ooEncryptionProvider (defined in ooBase.h , which is included by oo.h ) and overrides the appropriate methods.

The methods of class ooEncryptionProvider are:
virtual ooEncryptionStatus encryptPage(const ooUInt8* inStartAddress , ooUInt8* outStartAddress , unsigned numBytes , const ooId & oid , bool indexPage )

This method is called prior to writing a page of small objects to disk. It can be implemented to encrypt the data.

The parameters are:

The starting address in memory of the data to be converted. It will always be aligned on an 8-byte boundary.
The starting address in memory where the converted data should be placed. It will always be aligned on an 8-byte boundary.
The input and output addresses may or may not be the same, so the implementation of the method should not depend on that. If the method returns status other than oocEncryptionDone , it does not need to copy the data to the output location.
The length of the data, as a number of bytes. It will always be a multiple of 16 bytes so that block ciphers with a 128-bit block size may be used. (This value will be a little less than the database's page size, because there is some internal bookkeeping data that is not encrypted.)
This identifies the page. (The slot number is always 0).
If you do not want to encrypt catalog or schema pages, then the method should return oocEncryptionNotDone if either the database or container number is not greater than 1 (or if the database number is 65535 in a federation created before Release 9.0).
True if this is an index page, not a page of user objects. This is to enable encrypting index pages even if normal pages are not encrypted because object-level encryption is done instead. (Object encryption does not apply to index pages.)

The default method definition simply returns oocEncryptionNotDone to indicate that it did nothing. An override definition that performs page-level encryption should normally return oocEncryptionDone to indicate that the data was encrypted. It could instead return oocEncryptionUnauthorized to indicate that the user is not authorized to modify this page, in which case an exception of class ooAuthorizationException will be thrown to the application, and the transaction cannot be committed and must be aborted.

Important: None of these methods should ever throw an exception themselves because they are callbacks from low-level kernel code that may not be prepared to clean up when thrown past. Consequently, they should use try ... catch to handle any exceptions that might be thrown from within the method. Besides returning oocEncryptionError , the handler could first call ooSignal to register an error message to be included in the exception that will eventually be thrown to the application.
In addition, none of these methods should perform Objectivity/DB database operations.

virtual ooEncryptionStatus encryptObject(ooUInt8* startAddress , unsigned numBytes , const ooId & oid , ooTypeNumber typeN )

This method is called after a small object is closed (converted back to disk format). It can be implemented to encrypt the data.

The parameters are:

The starting address in memory of the data to be converted in-place. (In other words, this is both the input and output address.) It will always be aligned on a 4-byte boundary.
The length of the data, as a number of bytes. It will always be a multiple of 8 bytes. (In order to use a block cipher with a block size larger than 8 bytes, the class can be padded to allow the size to be rounded down to the appropriate boundary without exposing any sensitive data at the end.)
This identifies the object.
The object's type number.

The return values are the same as for encryptPage except that oocEncryptionUnauthorized is not applicable because objects must be closed even if they have not been modified.

virtual ooEncryptionStatus encryptLargeObject(ooUInt8* startAddress , unsigned numBytes , const ooId & oid , ooTypeNumber typeN )

This method is the same as encryptObject except that encryptObject is called on small objects and encryptLargeObject is called on large objects. (Note that encryptPage is not called on large object pages, so it combines page-level and object-level encryption.)

For large objects, the size given can be rounded up to a multiple of 16 bytes if necessary to match the encryption block size because the space after the object on the last page is not used.

The default method calls encryptObject , so in some cases it may be sufficient to implement just encryptObject and decryptObject .

virtual ooEncryptionStatus decryptPage(ooUInt8* startAddress , unsigned numBytes , const ooId & oid , bool indexPage )

This method is called after an encrypted page of small objects (a page for which encryptPage returned oocEncryptionDone ) has been read from disk into memory. The parameters are the same as for encryptPage , except that a single address is used for both input and output.

The default implementation simply returns oocEncryptionNotDone indicating that it does not know how to decrypt the data. The user-written override that implements decryption should return oocEncryptionDone to indicate successful decryption, or oocEncryptionUnauthorized if the user is not authorized to read the data. Any return value other than oocEncryptionDone causes an exception of class ooAuthorizationException to be thrown to the application, which will be unable to access the data it was trying to read.

virtual ooEncryptionStatus decryptObject(ooUInt8* startAddress , unsigned numBytes , const ooId & oid, ooTypeNumber typeN )

This method is called before opening an encrypted small object (an object for which encryptObject returned oocEncryptionDone ). The parameters are the same as for encryptObject . The return value is the same as for decryptPage .

virtual ooEncryptionStatus decryptLargeObject(ooUInt8* startAddress , unsigned numBytes , const ooId & oid , ooTypeNumber typeN )

This method is called before opening an encrypted large object (an object for which encryptLargeObject returned oocEncryptionDone ). The parameters are the same as for encryptLargeObject . The return value is the same as for decryptPage and decryptObject .

The default method calls decryptObject , so in some cases it may be sufficient to implement just encryptObject and decryptObject .

The ooEncryptionProvider class provides an enumeration type ooEncryptionStatus for the result values of the methods. The enumeration type ooEncryptionStatus has the following values:
Indicates that encryption or decryption was successful.
Indicates that the method chose not to perform encryption or does not know how to perform decryption.
Indicates failure of the operation due to lack of authorization. For a decryption method, this means that the user is not authorized to read the data. For an encryption method, it means that the user is not authorized to modify the data (this is useful only at the page level).
Indicates failure for some other reason.
The file ooException.h defines a new class ooAuthorizationException , which is derived from ooKernelException . (It has no additional public members.)

Implement the Plugin's Entry Point Function

The plugin library needs to implement the following global function:
extern "C" void* createPlugin(const char* pluginKey )
(On Windows, __declspec(dllexport) is also needed.)

The function should return a pointer to an instance of the user's subclass of ooEncryptionProvider . The methods of that instance will be called on subsequent page and object operations in the current process.

The argument value of this function will be the optional "key" string specified in the corresponding plugin specification file entry (not to be confused with an encryption key). The key argument is typically used to choose between multiple plugins implemented in the same library.

For example:

#include <oo.h>

#ifdef _DLL
#define DLL_EXPORT __declspec(dllexport)
#define DLL_EXPORT

class myEncryption : public ooEncryptionProvider
 // ... provide override methods here ...

extern "C" { DLL_EXPORT
	void* createPlugin(const char* pluginKey)
		if ( strcmp(pluginKey, "my encryption")==0 )
			return new myEncryption();

Install a Plugin Specification File

Objectivity/DB uses a plugin specification file to load the encryption plugin. The plugin specification file entry has the following characteristics:

  • The extension point name is EncryptionHook.
  • The plugin must be defined as a CppImplementation. The library value is the pathname of the shared library. The optional key value will be passed as the argument to the createPlugin function.

For example:

			<Plugin extensionPoint="EncryptionHook">
				<CppImplementation library="C:\myLibs\myLibrary.dll" key="my encryption"/>

This plugin specification is in a file with a .plugin suffix placed in the plugins directory of the Objectivity installation.

Platform-Specific Characteristics

Implementors of encryption methods should ensure that the encryption technique is not platform-dependent (unless only one platform will be used). For example, treating the data as an array of bytes instead of an array of words avoids byte-order dependency.

Performance Impact

A computationally-intensive encryption algorithm might degrade application performance.

Backward Compatibility

Database Format

This feature can be used with existing federations in either old (pre-Release 9.0) or new catalog formats.

The only change to the database format is that Objectivity/DB now uses a previously unused flag bit to mark encrypted pages or objects; pre-Release 10.0 applications will not understand the flag and will see meaningless (possibly invalid) data on attempting to read encrypted data.


No change is required to existing code for applications that do not use page and object encryption.

Related Documentation

Refer to the following sources for more information:

  • The information about extending Objectivity/DB features in the Objectivity/DB Administration manual in your Objectivity documentation.

Tuesday, February 19, 2013