Property Encryption #1786
injectives
announced in
Preview features
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Property Encryption allows Neo4j properties to be encrypted and decrypted on the driver side.
Property values are encrypted and encoded into bytes. The resulting bytes contain the encrypted value together with the
metadata required to decrypt it. The application is responsible for storing these bytes in a representation supported by
Neo4j property types. To decrypt a value, the application retrieves the stored bytes and provides them to the driver.
The feature is designed to be easy to use, with an opinionated approach to encryption and decryption. All official Neo4j
drivers are expected to support the feature, enabling interoperability between drivers when they are configured to use
compatible encryption settings.
Important
Preview Feature
The preview feature is a new feature that is a candidate for a future GA status.
It enables users to try the feature out and maintainers to refine and update it.
The preview features are not considered to be experimental, temporary or unstable.
However, they may change more rapidly, without following the usual deprecation cycle.
Most preview features are expected to be granted the GA status unless some unexpected conditions arise.
Note
This feature is available from version 6.3.0 onwards.
Note
At present, all encryption and decryption is manual. As an official Neo4j Driver feature, Property Encryption enables:
While Property Encryption API includes a more detailed overview, the following two examples demonstrate the basic usage of the API.
Encryption example:
Decryption example:
Supported types
Property Encryption supports encrypting Neo4j Database Property types, namely:
stored in lists), although lists in general cannot be stored as properties. Lists stored as properties cannot contain
null values.
Encryption profile
An encryption profile defines the settings and operating mode used by the driver when encrypting and decrypting values.
Each profile has a unique, user-defined name. The profile name is stored with encrypted values and allows drivers to
identify which profile must be used to decrypt a value.
Multiple profiles can be configured at the same time, providing each has a unique name.
Note
When driver interoperability is required, users are expected to configure each driver with compatible profiles.
Profiles are configured at the driver level using a driver configuration option:
PropertyEncryptionProfileis the base type for encryption profiles. At present, the driver provides one profile type:EnvelopePropertyEncryptionProfile. Additional profile types may be introduced in the future.Envelope profile
EnvelopePropertyEncryptionProfileenables envelope encryption of Neo4j properties.Envelope encryption separates the encryption of the data from the protection of the key used to encrypt that data. The
key used to encrypt the data is sometimes referred to as a Data Encryption Key (DEK). Depending on the implementation,
the encryption key may be the DEK itself or it may be derived from the DEK.
The DEK must itself be protected. When a separate Key Encryption Key (KEK) is used to protect the DEK, the process is
commonly referred to as key wrapping. Alternatively, a Key Encapsulation Mechanism (KEM) can be used to protect or
establish the secret material associated with the DEK. In the latter case, the terminology and exact mechanism depend on
the KEM being used, such as MK-KEM.
The envelope profile setup requires two fundamental components. These are covered in separate sections, but are briefly
introduced here:
Property values are encrypted using the following:
The
EnvelopePropertyEncryptionProfileprovides a builder for creating a profile instance:The builder has additional options that are introduced alongside the relevant concepts in later sections.
Key Encapsulation Service
Key Encapsulation Service is responsible for generating, encapsulating, and decapsulating data encryption keys. It
generates a new data encryption key together with its encapsulation, and can later decapsulate the encapsulation to
recover the data encryption key when it is needed for encryption or decryption.
The key encapsulation mechanism is implementation-specific. It may use key wrapping, symmetric or asymmetric
cryptography, a key management service (KMS), or a post-quantum key encapsulation mechanism such as ML-KEM.
The service is represented by
KeyEncapsulationServiceinterface that has 2 primary methods:encapsulate- supplies a new AES-256 key and its encapsulationdecapsulate- decapsulates an existing encapsulation to AES-256 keyFor users wishing to provide a non-blocking implementation, there is an
AsyncKeyEncapsulationServicevariant:The interface can be implemented to integrate different key encapsulation mechanisms. The driver also provides several
implementations, described in the following sections.
Local
The local implementation uses a user-provided AES-256
SecretKeyas a master key for encapsulating and decapsulatingdata encryption keys.
The encapsulation uses AES-GCM (
"AES/GCM/NoPadding") with the provided master key. The resulting encapsulationcontains a 256-bit AES data encryption key protected by the master key, together with a 96-bit (12-byte) initialization
vector (IV) and a 128-bit (16-byte) authentication tag.
Create a service instance:
AWS KMS
The AWS KMS implementation generates 256-bit AES data encryption keys locally and uses AWS KMS to encapsulate and
decapsulate those keys.
Note
This implementation is provided as a separate Neo4j Java Driver module, neo4j-java-driver-encryption-aws-kms, which
must be used together with the driver module.
Tip
It is recommended to use neo4j-java-driver-bom to manage compatible versions of the Neo4j Java Driver modules. See
BOM for more details.
Add dependencies in Maven:
Create a service instance:
The AWS KMS client is used for communication with AWS KMS. AWS credentials are resolved by the client using the
AWS SDK's default credential resolution mechanism.
Azure Key Vault
The Azure Key Vault implementation generates 256-bit AES data encryption keys locally and uses Azure Key Vault to
encapsulate and decapsulate those keys.
Note
This implementation is provided as a separate Neo4j Java Driver module, neo4j-java-driver-encryption-azure-keyvault,
which must be used together with the driver module.
Tip
It is recommended to use neo4j-java-driver-bom to manage compatible versions of the Neo4j Java Driver modules. See
BOM for more details.
Add dependencies in Maven:
Create a service instance:
Azure credentials are resolved using the Azure Identity library's default credential resolution mechanism.
The service caches up to 10
CryptographyAsyncClientinstances, keyed by Azure Key Vault key id. When the cache reachesits capacity, the least recently used client is evicted. To configure a different cache size, an overloaded
createmethod.
Google Cloud KMS
The Google Cloud KMS implementation generates 256-bit AES data encryption keys locally and uses Google Cloud KMS to
encapsulate and decapsulate those keys.
Note
This implementation is provided as a separate Neo4j Java Driver module,
neo4j-java-driver-encryption-google-cloud-kms, which must be used together with the driver module.
Tip
It is recommended to use neo4j-java-driver-bom to manage compatible versions of the Neo4j Java Driver modules. See
BOM for more details.
Add dependencies in Maven:
Create a service instance:
Encapsulated Key Record Repository
An Encapsulated Key Record Repository is a user-provided repository for storing encapsulated data keys and their
associated metadata.
Each encapsulated key record has a globally unique and immutable identifier.
Important
The repository implementation is responsible for assigning globally unique and immutable key identifiers.
In addition, the repository is also responsible for enforcing alias uniqueness.
The repository is represented by
EncapsulatedKeyRecordRepositoryinterface that has 5 primary methods:create- creates a new key recordfindById- finds key by idfindByAlias- finds key by aliassetAliasById- sets key alias by iddeleteById- deletes key by idFor users wishing to provide a non-blocking implementation, there is an
AsyncEncapsulatedKeyRecordRepositoryvariant:Note
An implementation of repository is supplied by the user.
Below is a sample implementation:
Property Encryption API
The Property Encryption API is exposed through
PropertyEncryption, which is available directly from theDriverobject. This makes the API easy to access, particularly in existing applications where the driver object is already
available.
Obtain PropertyEncryption:
Property Encryption is also available in asynchronous and reactive variants.
Those variants may be obtained via
Driver#propertyEncryption(Class<T>)method.Obtain AsyncPropertyEncryption:
Obtain ReactivePropertyEncryption with
java.util.concurrent.Flowtypes:Obtain ReactivePropertyEncryption with
org.reactivestreamstypes:EncapsulatedKeyManager
The Envelope Profile requires data keys to exist before they can be used to encrypt or decrypt property values.
Creating a data key involves obtaining a new data encryption key and its encapsulation from the
Key Encapsulation Service and creating the corresponding record in the Encapsulated Key Record Repository.
To simplify these operations,
PropertyEncryptionprovides anEncapsulatedKeyManagerthroughPropertyEncryption#keyManager()when a single profile is configured andPropertyEncryption#keyManager(String)whenmultiple profiles are configured.
Obtain key manager:
Note
A data key can be referenced by its globally unique identifier or, if assigned, by an alias. Both are String values.
The key identifier is immutable and globally unique, assigned by the key repository. The alias is a mutable,
application-level reference that can be reassigned to a different key over time.
Aliases allow applications to refer to keys using stable application-level names without having to reference the key's
identifier.
The key manager provides operations to create, find, and delete keys. It also provides operations to set and delete key
aliases. When Caching is enabled, key management operations update the Key Cache and Key Alias Index as necessary.
Create a data key with an alias:
The returned
EncapsulatedKeyhas accessors for:Find key by alias:
Set alias by id:
Delete alias by id:
Delete key by id:
PropertyEncryptionRequest
Property values are encrypted by creating a
PropertyEncryptionRequestand providing it toPropertyEncryption.PropertyEncryptionRequest#builder()returns a staged builder for creating aPropertyEncryptionRequest.Encrypt value:
usingKeyIdvariant.Important
The encrypted value always references the encryption key identifier, which is expected to be immutable and globally
unique. This ensures that the identifier used by the encrypted value is stable, even when a key alias is used in the
encryption request.
Additional Authenticated Data (AAD) is optional, non-secret data that is authenticated together with the encrypted
value but is not itself encrypted. The same AAD must be provided during decryption. Otherwise, decryption fails.
Important
It is recommended to use AAD to bind an encrypted value to application-specific context where possible, such as a user
identifier. This ensures that the context is authenticated when the value is later decrypted.
AAD should not contain confidential information.
Only the following Neo4j property types are supported as AAD:
NFCbefore providing them to the driver when bothencrypting and decrypting values
PropertyDecryptionRequest
Encoded encrypted values are decrypted by creating a
PropertyDecryptionRequestand providing it toPropertyEncryption.PropertyDecryptionRequest#builder()returns a staged builder for creating aPropertyDecryptionRequest.Decrypt value:
byte[].The AAD step provides a choice of how AAD is handled. An external AAD can be provided using one of the
withAAD(...)methods. This AAD must be supplied independently during decryption and therefore can bind the encrypted value to
external application context, such as a user identifier.
Alternatively,
withoutExternalAAD()can be used to rely on the AAD configuration recorded in the encrypted valuemetadata. If AAD was used when the value was encrypted, that AAD is used during decryption. If no AAD was used, no
effective AAD is used during decryption. Because this AAD is obtained from the encrypted value itself, it does not
bind the value to an independently supplied external context.
Important
It is recommended to provide AAD externally when possible, especially when the encrypted value was bound to
application-specific context during encryption. The externally provided AAD must match the AAD used during encryption.
Caching
The Envelope Profile supports 2 related caches:
Note
Each profile instance maintains its own dedicated caches.
Key Cache
The driver caches decapsulated data encryption keys by default to avoid repeatedly resolving and decapsulating the same
key.
Depending on the Envelope Profile and Encapsulated Key Record Repository implementations, resolving a
key may require network exchanges. Caching can therefore reduce the number of repeated key resolution operations.
The key cache is keyed by the key's globally unique identifier and has a configurable maximum size and time-to-live
(TTL). The default size is
100and TTL is15minutes.The key cache can be configured when creating an Envelope Profile:
Configure Key Cache:
The key cache is bounded and uses a least-recently-used (LRU) eviction policy when its configured maximum size is
reached. Entries that have exceeded their configured TTL are treated as cache misses and are not used.
The key cache can also be disabled:
Disable Key Cache:
Key Alias Index
Aliases are resolved through a key alias index that maps aliases to key identifiers. The alias index does not contain
key material.
The alias index has its own configurable maximum size and TTL. The default size is
100and TTL is15seconds.Note
This allows alias mappings to expire independently of cached keys and limits the period for which a driver may use a
stale alias after it has been reassigned.
The alias index can be configured when creating an Envelope Profile:
Customize Key Alias Index:
Like the key cache, the alias index is bounded and uses a least-recently-used (LRU) eviction policy when its configured
maximum size is reached. Entries that have exceeded their configured TTL are treated as cache misses and are not used.
The key alias index is disabled when the key cache is disabled. It can also be disabled independently:
Disable Key Alias Index:
Security Providers
Cryptographic operations for Property Encryption are performed through the Java Cryptography Architecture (JCA) and
related Java security APIs rather than being implemented directly by the driver.
By default, the driver uses the cryptographic implementations selected by the Java runtime. Where applicable, users can
explicitly provide a
java.security.Providerandjava.security.SecureRandomto control the cryptographicimplementations used by the driver.
Important
The cryptographic algorithms and parameters used by this feature, including key sizes, initialization vector (IV) sizes,
and authentication tag sizes, have been selected with FIPS requirements in mind. However, FIPS compliance depends on
more than the algorithms and parameters used by the driver. It can also depend on the cryptographic provider or
validated cryptographic module, its configuration, the runtime environment, key management, storage, and other aspects
of the deployment that are outside the driver's control.
Users requiring FIPS-compliant operation are responsible for ensuring that the driver and its surrounding environment
are configured appropriately for their requirements. The driver uses the provider and secure random source supplied by
the user, subject to the requirements documented in the relevant Javadoc.
Provider Example
The following example uses Bouncy Castle FIPS
2.1.1(NIST 4943 FIPS 140-3 Active, check NIST directly for the latestvalidation status).
Add dependencies in Maven:
Select Security Provider:
A similar approach can be used with
org.bouncycastle:bc-fips:1.0.2.4(NIST 4616 FIPS 140-2 Historical, check NISTdirectly for the latest validation status).
All reactions