Skip to main content

User Manual

This manual is designed to be readable by someone with basic knowledge of Sequelize. It is recommend to have a high-level understanding of D1 Generic, but it is not a strict requirement.

Overview

The integration works by encrypting and decrypting data transparently, using D1 Generic when querying or storing in the database. Selected parts of the data is encrypted from the application to the database in such a way that the database itself never receives the data in plain text.

When data is stored in the database the data will be encrypted by making a request to the D1 service, before it is stored in the database. An exception is thrown if the application does not have permissions to encrypt data or the D1 service is not available.

When data is queried, data will automatically be decrypted by making a request to the D1 service, before the data is returned to the caller. If the decryption for some reason fails, for example if the application does not have access to the data or the data is corrupt, an exception will be thrown and the data will not be returned to the caller.

Supported data types

The following data types are supported:

  • DataTypes.STRING
  • DataTypes.BLOB

In the future, more data types will be supported.

Storage format

Encrypted data is stored in the column as defined by the data model, but the size of the column increases, as the object ID of the encrypted data is prepended to the data and the encryption itself has some overhead, see the D1 Generic documentation for more information about object IDs.

Overhead

Text data

The overhead of encrypting text data is:

  • Object ID prefix: 36 bytes
  • Encryption overhead: 48 bytes
  • Base64 encoding: 33 - 36%

Total overhead: Text + 84 bytes + ~34%

Binary data

The overhead of encrypting binary data is:

  • Object ID prefix: 36 bytes
  • Encryption overhead: 48 bytes

Total overhead: Data + 84 bytes

Example

Consider a databases table with the following schema:

Column nameData type
IdINT
NameVARCHAR(100)
SensitiveDataVARCHAR(MAX)

Without encryption the content could look like this:

IdNameSensitiveData
1John DoeJohns secret data
2Jane DoeJanes secret data

When the data is encrypted the content will look similar to:

IdNameSensitiveData
1John DoeTURaa1pqUmhOR1V0WkRJM05TMDBNekEzTFRnNE9XUXRPR00yTlRjMk5Ea3lPVEpsVytrdXJHcDYveTR1NEM3Q0xsL2NMbUl1TGk0dUxpNHVSVVRSTGk1QVl5ND0=
2Jane DoeTm1JMU1XTm1NV1l0TnpnMVppMDBZMlJsTFdKa05qRXRaRFkwTXpaaU1tSmlOV1E0cFM1UVlDREc5UzVMOUt1L2VzcXhaeTR1WDhzdzdrdzZXRmMyNnRyRXBMdz0=

As you can see the size of the data increases for a couple of reasons:

  • Object ID is added to the data
  • Encryption overhead
  • Base64 encoding (text data only)

Installation

The latest version of CYBERCRYPT D1 Sequelize can be installed through npm.org, using the following command:

npm install @cybercryptio/d1-sequelize

Usage

Choose confidential properties

In order to mark a property as confidential, you have to add the confidential attribute to the property.

Document = sequelize.define('Document', {
document: {
type: DataTypes.STRING,
confidential: true // Here
},
metadata: DataTypes.STRING
})

Initialize D1 Sequelize

D1 Sequelize must be able to communicate with the D1 service. This is done by initializing the integration like this:

const { D1GenericClient, UsernamePasswordCredentials } = require('@cybercryptio/d1-client-nodejs')
const d1Sequelize = require('../../index.js')

const endpoint = 'localhost:9000'
const uid = "UID"
const password = "PASSWORD"
const creds = new UsernamePasswordCredentials(uid, password, endpoint)
const client = new D1GenericClient(endpoint, creds)

d1Sequelize.d1Init(client)

Add hooks

In order for the encryption and decryption to work, you have to add two hooks to the model or globally.

const d1Sequelize = require('../../index.js')

Document = sequelize.define('Document', {
document: {
type: DataTypes.STRING,
confidential: true
},
metadata: DataTypes.STRING
}, {
hooks: {
beforeSave: d1Sequelize.encryptHook, // Here
afterFind: d1Sequelize.decryptHook // Here
}
})