Skip to content

Application Level Encryption API

Cloudproof Encryption provides libraries and tools to encrypt and securely index large repositories of data with advanced, high-performance security primitives.

See the use cases and benefits and a description of the cryptosystems used.

The libraries are available in multiple languages to facilitate encryption close to the data source and decryption close to the decryption target, including mobile devices and browsers.

This section describes the Application Level Encryption API, the Encrypted Search API is on this page.

Implementations and quick start

The application-level encryption scheme is called CoverCrypt. It is open-source and written in Rust. For the cryptographic documentation and implementation details, please check its Github repository.

Unless low-level programming in Rust, implementers should use Covercrypt through the various cloudproof_xxx user libraries, where xxx is either Javascript, Java, Python, or Flutter. All these libraries are open-source and available on Github

The user libraries all contain extensive tests, and it is highly recommended to start by hacking those tests.

Setup

It is possible to create keys using the libraries; however, it is more likely that you will want to store them in a KMS. Please go to the KMS section to fetch and run a local KMS.

The library is published on npm: simply install the library in your package.json

npm install cloudproof_js

The library contains web assembly for cryptographic speed

You need Java 8+ and Maven version 3+ The cloudproof_java library is deployed on Maven central. Add the library to your POM

<dependency>
  <groupId>com.cosmian</groupId>
  <artifactId>cloudproof_java</artifactId>
  <version>3.0.0</version>
  <type>jar</type>
</dependency>

Encryption and decryption can be accomplished in the KMS, however, you will likely want to perform them locally using the native library, compiled from Rust. The cloudproof_java library leverages Java Native Access to call the native library.

Builds of the native library are already provided inside the Java library for the following architectures:

  • linux-x86-64 for GLIBC 2.17+
  • darwin-x86-64
  • win32-x86-64

To build the library yourself, please see the CoverCrypt project. In your java project, the library build needs to be placed inside in

  • src/main/resources/linux-x86-64 folder for a Linux Intel machine
  • src/main/resources/linux-amd64 folder for a Linux AMD machine
  • src/main/resources/darwin folder for a Mac running MacOS
  • src/main/resources/win32-x86 folder for a Windows machine

To run tests only, place the library inside the corresponding folder above replacing main with test

Check the JNA documentation for alternative locations for the native library.

To use the native library, simply instantiate a CoverCrypt object.

static final CoverCrypt coverCrypt = new CoverCrypt();

The instance is thread-safe and can be used for all subsequent calls.

The library is available on PyPI:

pip install cloudproof_py

The library is published on pub.dev as a Dart library: https://pub.dev/packages/cloudproof. To install it:

flutter pub add cloudproof

The library contains cryptographic native libraries called through FFI functions.

Creating a policy

A Policy is specified by Policy Axes, defining an n-dimensional matrix of authorizations/partitions. A user must possess keys with access policies satisfying the attributes from these n axes to be able to decrypt files.

In this demo, we will create a Policy that combines two axes, a security level, and a department. A user will be able to decrypt data only if it possesses a key with a sufficient security level and the code for the department.

Policy Axes

The Policy is defined by two Policy Axes, thus defining a two-dimensional matrix of authorizations. A user must possess keys with attributes from these two axes to be able to decrypt files.

Security Level Axis

The first Policy Axis is the ‘Security Level’ axis and is a hierarchical axis made of 3 levels: Protected, Confidential, and Top Secret. This axis is hierarchical: when a user is granted access to level n, it is automatically granted access to all levels below n. The attributes must be provided in ascending order.

Department Security Axis

The second Policy Axis is the Department axis and is made of 3 values: HR, MKG, and FIN. This axis is not hierarchical: granting access to an attribute of this axis to a user does not give access to any other attribute. Each attribute must be granted individually.

const policy = new Policy([
    new PolicyAxis(
        "Department",
        ["FIN", "HR", "MKG"],
        false
    ),
    new PolicyAxis(
        "Security Level",
        ["Protected", "Confidential", "Top Secret"],
        true
    ),
])
Policy policy = new Policy()
        // Integer.MAX_VALUE is an arbitrary value that represents
        // the maximum number of attributes that can be
        // used in policy
        .addAxis("Security Level",
            new String[] {
                "Protected",
                "Confidential",
                "Top Secret"
            },
            true) // <- hierarchical axis
        .addAxis("Department",
            new String[] {
                "FIN",
                "MKG",
                "HR"
            },
            false); // <- non hierarchical axis
from cloudproof_py.cover_crypt import Policy, PolicyAxis

policy = Policy()
policy.add_axis(
    PolicyAxis(
        "Security Level",
        ["Protected", "Confidential", "Top Secret"],
        hierarchical=True,
    )
)
policy.add_axis(
    PolicyAxis("Department", ["FIN", "MKG", "HR"], hierarchical=False)
)

Generating the master keys

The Master Authority possesses the key pair for the given Policy:

  • a Master Private Key which is used to generate user keys
  • and a Public Key which is used to encrypt files with any combination of attributes. Since it cannot decrypt, the public key can be freely distributed to encrypting systems.

Keys can be generated locally using the WASM code

To generate keys you can use a Cosmian KMS server and, unless you run in dev mode, an API Key to authenticate to the server.

To generate keys from a Cosmian KMS server, instantiate a KmsClient with its URL and, unless you run in dev mode, an API Key to authenticate to the server.

static final KmsClient kmsClient = new KmsClient(
    [KMS_SERVER_URL], [YOUR_API_KEY]
);

// create the Master Keys.

String[] ids = kmsClient.createCoverCryptMasterKeyPair(policy);
String privateMasterKeyUniqueIdentifier = ids[0];
String publicMasterKeyUniqueIdentifier = ids[1];

The master keys can be exported from the KMS and their bytes recovered to use with the native library

// export the private master key
PrivateKey privateMasterKey = kmsClient.retrieveCoverCryptPrivateMasterKey(privateMasterKeyUniqueIdentifier);
byte[] privateMasterKeyBytes = privateMasterKey.bytes();

// export the public key
PublicKey publicKey = kmsClient.retrieveCoverCryptPublicMasterKey(publicMasterKeyUniqueIdentifier);
byte[] publicKeyBytes = publicKey.bytes();

To use the native library, simply instantiate a CoverCrypt object.

static final CoverCrypt coverCrypt = new CoverCrypt();

The instance is thread safe and can be used for all subsequent calls.

MasterKeys masterKeys = coverCrypt.generateMasterKeys(policy);
byte[] privateMasterKeyBytes = masterKeys.getPrivateKey();
byte[] publicKeyBytes = masterKeys.getPublicKey();
from cloudproof_py.cover_crypt import CoverCrypt

CoverCryptInstance = CoverCrypt()
master_private_key, public_key = CoverCryptInstance.generate_master_keys(policy)

Encrypting Data

Data is encrypted using the Public Key and a boolean encryption policy that determines the target partitions of the ciphertext.

Anyone who has access to the Public Key can encrypt data, however, only users possessing user keys with the right access policy can decrypt the ciphertext.

A ciphertext is the concatenation of a header and encrypted content.

  • The encrypted content is a plaintext symmetrically encrypted using an ephemeral secret key (i.e. a random key generated on the fly).
  • The header is the encapsulation of the ephemeral key, using the public key and the encryption policy, concatenated with some optional metadata. The header metadata, if present, are also symmetrically encrypted using the ephemeral key.

Header and encrypted content can be generated separately using the various APIs. Check the inline documentation of the various languages and the test suites for details.

The code below shows the encryption of 3 messages with 3 different encryption policies targeting 3 different partitions.

Encrypting data is done using the encrypt() function which calls the WASM function.

// a protected marketing message

const { CoverCryptHybridEncryption } = await CoverCrypt();

const protectedMkgData = new TextEncoder().encode("protected_mkg_message")

let encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const protectedMkgCiphertext = encrypter.encrypt(
  "Department::MKG && Security Level::Protected",
  protectedMkgData
)
// a top-secret marketing message

const { CoverCryptHybridEncryption } = await CoverCrypt();

const topSecretMkgData = new TextEncoder().encode("top_secret_mkg_message")
encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const topSecretMkgCiphertext = encrypter.encrypt(
  "Department::MKG && Security Level::Top Secret",
  topSecretMkgData
)
// a protected finance message

const { CoverCryptHybridEncryption } = await CoverCrypt();

const protectedFinData = new TextEncoder().encode("low_secret_fin_message")
encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const protectedFinCiphertext = encrypter.encrypt(
  "Department::FIN && Security Level::Protected",
  protectedFinData
)

Encrypting data is done using the coverCryptEncrypt() function which calls the KMS to encrypt

// a protected marketing message

const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

const protectedMkgData = new TextEncoder().encode("protected_mkg_message")

const protectedMkgCiphertext = await client.coverCryptEncrypt(
  publicMasterKeyUID,
  "Department::MKG && Security Level::Protected",
  protectedMkgData
)
// a top-secret marketing message

const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

const topSecretMkgData = new TextEncoder().encode("top_secret_mkg_message")

const topSecretMkgCiphertext = await client.coverCryptEncrypt(
  publicMasterKeyUID,
  "Department::MKG && Security Level::Top Secret",
  topSecretMkgData
)
// a protected finance message

const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

const protectedFinData = new TextEncoder().encode("low_secret_fin_message")

const protectedFinCiphertext = await client.coverCryptEncrypt(
  publicMasterKeyUID,
  "Department::FIN && Security Level::Protected",
  protectedFinData
)

Encrypting using the native library is fast and provides many options.

a protected marketing message

byte[] protectedMkgData = "protectedMkgMessage".getBytes(StandardCharsets.UTF_8);
String protectedMkgEncryptionPolicy = "Department::MKG && Security Level::Protected";
byte[] protectedMkgCT = coverCrypt.encrypt(
    policy,
    publicKeyBytes,
    protectedMkgEncryptionPolicy,
    protectedMkgData);

a top-secret marketing message

byte[] topSecretMkgData = "topSecretMkgMessage".getBytes(StandardCharsets.UTF_8);
String topSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Top Secret";
byte[] topSecretMkgCT = coverCrypt.encrypt(
    policy,
    publicKeyBytes,
    topSecretMkgEncryptionPolicy,
    topSecretMkgData);

a protected finance message

byte[] protectedFinData = "protectedFinMessage".getBytes(StandardCharsets.UTF_8);
String protectedFinEncryptionPolicy = "Department::FIN && Security Level::Protected";
byte[] protectedFinCT = coverCrypt.encrypt(
    policy,
    publicKeyBytes,
    protectedFinEncryptionPolicy,
    protectedFinData);

Encrypting using the KMS is possible (and compatible with the native library) but is inefficient compared to using the native library, due to the added I/O and stress on the KMS server.

The only reason to encrypt using the KMS is to enable a “pure” java solution without native code (which is, for instance, a requirement for a plugin in an Oracle database )

a protected marketing message

byte[] protectedMkgData = "protectedMkgMessage".getBytes(StandardCharsets.UTF_8);
String protectedMkgEncryptionPolicy = "Department::MKG && Security Level::Protected";
byte[] protectedMkgCT = kmsClient.coverCryptEncrypt(
    publicMasterKeyUniqueIdentifier,
    protectedMkgData,
    protectedMkgEncryptionPolicy);

a top-secret marketing message

byte[] topSecretMkgData = "topSecretMkgMessage".getBytes(StandardCharsets.UTF_8);
String topSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Top Secret";
byte[] topSecretMkgCT = kmsClient.coverCryptEncrypt(
    publicMasterKeyUniqueIdentifier,
    topSecretMkgData,
    topSecretMkgEncryptionPolicy);

a protected finance message

byte[] protectedFinData = "protectedFinMessage".getBytes(StandardCharsets.UTF_8);
String protectedFinEncryptionPolicy = "Department::FIN && Security Level::Protected";
byte[] protectedFinCT = kmsClient.coverCryptEncrypt(
    publicMasterKeyUniqueIdentifier,
    protectedFinData,
    protectedFinEncryptionPolicy);

Encrypting data is done using the encrypt() function that concatenates the header (encapsulation of the ephemeral symmetric key) and the symmetrically encrypted data.

These can be done separately; see CoverCrypt.encrypt_header

a protected marketing message

protected_mkg_data = b"protected_mkg_message"
protected_mkg_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::MKG && Security Level::Protected",
    public_key,
    protected_mkg_data
)

a top secret marketing message

topSecret_mkg_data = b"top_secret_mkg_message"
topSecret_mkg_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::MKG && Security Level::Top Secret",
    public_key,
    topSecret_mkg_data
)

a low secret finance message

protected_fin_data = b"protected_fin_message"
protected_fin_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::FIN && Security Level::Protected",
    public_key,
    protected_fin_data
)

a protected marketing message

a top secret marketing message

a low secret finance message

Generating User Decryption Keys

User Decryption Keys are generated from the Master Private Key using Access Policies. Access Policies are monotonous boolean expressions combining policy attributes.

Let us create 2 users with different access policies to illustrate their effect.

User Decryption Keys can be generated by calling the local WASM

the confidential marketing user

This user can decrypt messages from the marketing department only, with a security level of Confidential or below:

const { CoverCryptKeyGeneration } = await CoverCrypt();

const keygen = new CoverCryptKeyGeneration()

const confidentialMkgUserKeyBytes =
    keygen.generateUserSecretKey(
        masterSecretKeyBytes,
        "Department::MKG && Security Level::Confidential",
        policy,
    )

the top secret marketing financial user

This user can decrypt messages from the marketing department OR the financial department with a security level of Top Secret or below:

const topSecretMkgFinUserKeyBytes =
    keygen.generateUserSecretKey(
        masterSecretKeyBytes,
        "(Department::MKG || Department::FIN) && Security Level::Top Secret",
        policy,
    )

the confidential marketing user

This user can decrypt messages from the marketing department only, with a security level of Confidential or below:

const confidentialMkgAccess =
  "Department::MKG && Security Level::Confidential"
const confidentialMkgUserKeyUid = await client.createCoverCryptUserDecryptionKey(
  confidentialMkgAccess,
  privateMasterKeyUID
)

the top secret marketing financial user

This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below

const topSecretMkgFinAccess =
  "(Department::MKG || Department::FIN) && Security Level::Top Secret"
const topSecretMkgFinUserKeyUid = await client.createCoverCryptUserDecryptionKey(
  topSecretMkgFinAccess,
  privateMasterKeyUID
)
const topSecretMkgFinUserKey = await client.retrieveCoverCryptUserDecryptionKey(
  topSecretMkgFinUserKeyUid
)
const topSecretMkgFinUserKeyBytes = topSecretMkgFinUserKey.bytes()

exporting the keys

As with the master keys, the user keys can be exported to be used with the native library

    const confidentialMkgUserKey = await client.retrieveCoverCryptUserDecryptionKey(
  confidentialMkgUserKeyUid
)
const confidentialMkgUserKeyBytes = confidentialMkgUserKey.bytes()

const topSecretMkgFinUserKey = await client.retrieveCoverCryptUserDecryptionKey(
  topSecretMkgFinUserKeyUid
)
const topSecretMkgFinUserKeyBytes = topSecretMkgFinUserKey.bytes()

the confidential marketing user

This user can decrypt messages from the marketing department only, with a security level of Confidential or below:

String confidentialMkgUserKeyUid = kmsClient.createCoverCryptUserDecryptionKey(
    "Department::MKG && Security Level::Confidential",
    privateMasterKeyUniqueIdentifier);

the top secret marketing financial user

This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:

String topSecretMkgFinUserKeyUid = kmsClient.createCoverCryptUserDecryptionKey(
    "(Department::MKG || Department::FIN) && Security Level::Top Secret",
    privateMasterKeyUniqueIdentifier);

exporting the keys

As with the master keys, the user keys can be exported to be used with the native library

PrivateKey confidentialMkgUserKey_ =
kmsClient.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid);
PrivateKey topSecretMkgFinUserKey = kmsClient.retrieveCoverCryptUserDecryptionKey(topSecretMkgFinUserKeyUid);

User keys can be locally generated using the native library

the confidential marketing user

This user can decrypt messages from the marketing department only, with a security level of Confidential or below:

byte[] confidentialMkgUserKey = coverCrypt.generateUserPrivateKey(
        privateMasterKeyBytes,
        "Department::MKG && Security Level::Confidential",
        policy);

the top secret marketing financial user

This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:

byte[] topSecretMkgFinUserKeyUid = coverCrypt.generateUserPrivateKey(
        privateMasterKeyBytes,
        "(Department::MKG || Department::FIN) && Security Level::Top Secret",
        policy);

the confidential marketing user

This user can decrypt messages from the marketing department only, with a security level of Confidential or below:

confidential_mkg_userKey = CoverCryptInstance.generate_user_secret_key(
    master_private_key,
    "Department::MKG && Security Level::Confidential",
    policy
)

the top secret marketing financial user

This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:

topSecret_mkg_fin_userKey = CoverCryptInstance.generate_user_secret_key(
    master_private_key,
    "(Department::MKG || Department::FIN) && Security Level::Top Secret",
    policy
)

the confidential marketing user

This user can decrypt messages from the marketing department only, with a security level of Confidential or below:

the top secret marketing financial user

This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:

Decrypting Ciphertexts

The confidential marketing user can successfully decrypt a protected marketing message:

const { CoverCryptHybridDecryption } = await CoverCrypt();

const protectedMkgCleartext = new CoverCryptHybridDecryption(
  confidentialMkgUserKeyBytes
).decrypt(protectedMkgCiphertext)
assert(protectedMkgCleartext, protectedMkgData)
const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

const protectedMkgCleartext = await client.coverCryptDecrypt(confidentialMkgUserKeyUid, protectedMkgCiphertext)
assert(protectedMkgCleartext, protectedMkgData)
DecryptedData protectedMkg = kmsClient.coverCryptDecrypt(confidentialMkgUserKeyUid, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg.getPlaintext());
DecryptedData protectedMkg = coverCrypt.decrypt(confidentialMkgUserKey, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg.getPlaintext());
protected_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    confidential_mkg_userKey,
    protected_mkg_ciphertext
)
assert(protected_mkg_plaintext == protected_mkg_data)

.. however, it can neither decrypt a marketing message with higher security:

const { CoverCryptHybridDecryption } = await CoverCrypt();

try {
  // will throw
  new CoverCryptHybridDecryption(confidentialMkgUserKey).decrypt(
    topSecretMkgCiphertext
  )
} catch (error) {
  // ==> the user is not able to decrypt
}
const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

try {
  // will throw
  await client.coverCryptDecrypt(confidentialMkgUserKeyUid, topSecretMkgCiphertext)
} catch (error) {
  // ==> the user is not able to decrypt
}
try {
    kmsClient.coverCryptDecrypt(confidentialMkgUserKeyUid, topSecretMkgCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}
try {
    coverCrypt.decrypt(confidentialMkgUserKey, topSecretMkgCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}
try:
    # will throw
    CoverCryptInstance.decrypt(confidential_mkg_userKey, topSecret_mkg_ciphertext)
except Exception as e:
    # ==> the user is not be able to decrypt

… nor decrypt a message from another department even with lower security:

const { CoverCryptHybridDecryption } = await CoverCrypt();

try {
  // will throw
  new CoverCryptHybridDecryption(confidentialMkgUserKey).decrypt(
    protectedFinCiphertext
  )
} catch (error) {
  // ==> the user is not able to decrypt
}
const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

try {
  // will throw
  await client.coverCryptDecrypt(confidentialMkgUserKeyUid, protectedFinCiphertext)
} catch (error) {
  // ==> the user is not able to decrypt
}
try {
    kmsClient.coverCryptDecrypt(confidentialMkgUserKeyUid, protectedFinCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}
try {
    coverCrypt.decrypt(confidentialMkgUserKey, protectedFinCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}
try:
    # will throw
    CoverCryptInstance.decrypt(confidential_mkg_userKey, protected_fin_ciphertext)
except Exception as e:
    # ==> the user is not be able to decrypt

As expected, the top-secret marketing financial user can successfully decrypt all messages

const { CoverCryptHybridDecryption } = await CoverCrypt();

// protectedMkgCiphertext
const protectedMkgCleartext2 = new CoverCryptHybridDecryption(
  topSecretMkgFinUserKeyBytes
).decrypt(protectedMkgCiphertext)
assert(protectedMkgData, protectedMkgCleartext2)

// protectedFinCiphertext
const topSecretMkgCleartext = new CoverCryptHybridDecryption(
  topSecretMkgFinUserKeyBytes
).decrypt(topSecretMkgCiphertext)
assert(topSecretMkgData, topSecretMkgCleartext)

// protectedFinCiphertext
const protectedFinCleartext = new CoverCryptHybridDecryption(
  topSecretMkgFinUserKeyBytes
).decrypt(protectedFinCiphertext)
assert(protectedFinData, protectedFinCleartext)
const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

// protectedMkgCiphertext
const protectedMkgCleartext2 = await client.coverCryptDecrypt(topSecretMkgFinUserKeyUid, protectedMkgCiphertext)
assert(protectedMkgData, protectedMkgCleartext2)

// protectedFinCiphertext
const topSecretMkgCleartext = await client.coverCryptDecrypt(topSecretMkgFinUserKeyUid, topSecretMkgCiphertext)
assert(topSecretMkgData, topSecretMkgCleartext)

// protectedFinCiphertext
const protectedFinCleartext = await client.coverCryptDecrypt(topSecretMkgFinUserKeyUid, protectedFinCiphertext)
assert(protectedFinData, protectedFinCleartext)
DecryptedData protectedMkg_ = kmsClient.coverCryptDecrypt(topSecretMkgFinUserKeyUid, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg_.getPlaintext());

DecryptedData topSecretMkg_ = kmsClient.coverCryptDecrypt(topSecretMkgFinUserKeyUid, topSecretMkgCT);
assert Arrays.equals(topSecretMkgData, topSecretMkg_.getPlaintext());

DecryptedData protectedFin_ = kmsClient.coverCryptDecrypt(topSecretMkgFinUserKeyUid, protectedFinCT);
assert Arrays.equals(protectedFinData, protectedFin_.getPlaintext());
DecryptedData protectedMkg_ = coverCrypt.decrypt(topSecretMkgFinUserKeyUid, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg_.getPlaintext());

DecryptedData topSecretMkg = coverCrypt.decrypt(topSecretMkgFinUserKeyUid, topSecretMkgCT);
assert Arrays.equals(topSecretMkgData, topSecretMkg.getPlaintext());

DecryptedData protectedFin = coverCrypt.decrypt(topSecretMkgFinUserKeyUid, protectedFinCT);
assert Arrays.equals(protectedFinData, protectedFin.getPlaintext());
protected_mkg_plaintext2, _ = CoverCryptInstance.decrypt(
    topSecret_mkg_fin_userKey,
    protected_mkg_ciphertext
)
assert(protected_mkg_plaintext2 == protected_mkg_data)

topSecret_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    topSecret_mkg_fin_userKey,
    topSecret_mkg_ciphertext
)
assert(topSecret_mkg_plaintext == topSecret_mkg_data)

protected_fin_plaintext, _ = CoverCryptInstance.decrypt(
    topSecret_mkg_fin_userKey,
    protected_fin_ciphertext
)
assert(protected_fin_plaintext == protected_fin_data)

Rotating Attributes

At any time the Master Authority can rotate an attribute.

When that happens future encryption of data for a given attribute cannot be decrypted with keys that are not “refreshed” for that attribute.

It is best to perform attribute rotations using the KMS: the master keys will be automatically rekeyed and as long as a user key is active in the KMS (the key has not been revoked), it will also be automatically rekeyed.

rotating the Department::MKG attribute

Before rotating attributes, let us make a local copy of the current confidential marketing user to show what happens to non-refreshed keys after the attribute rotation.

const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

// retrieve the key
const oldConfidentialMkgUserKey =
  await client.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid)

// Now rotate the MKG attribute - all active keys will be rekeyed, the new policy should be used to encrypt
const updatedPolicy = client.rotateCoverCryptAttributes(privateMasterKeyUID, ["Department::MKG"])
// retrieve the key
PrivateKey oldConfidentialMkgUserKey =
    kmsClient.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid);

// Now rotate the MKG attribute - all active keys will be rekeyed
kmsClient.rotateCoverCryptAttributes(privateMasterKeyUniqueIdentifier,
    new Attr[] {new Attr("Department", "MKG")});
from cloudproof_py.cover_crypt import Attribute

# make a copy of the current user key
old_confidential_mkg_userKey = confidential_mkg_userKey.deep_copy()

# rotate MKG attribute
policy.rotate(Attribute("Department", "MKG"))

# update master keys
CoverCryptInstance.update_master_keys(policy, master_private_key, public_key)

# update user key
CoverCryptInstance.refresh_user_secret_key(
    confidential_mkg_userKey,
    "Department::MKG && Security Level::Confidential",
    master_private_key,
    policy,
    keep_old_accesses=True
)

creating a new confidential marketing message

The rekeyed public key is exported from the KMS to encrypt a new marketing confidential message using the native library.

const { CoverCryptHybridEncryption } = await CoverCrypt();

// retrieve the rekeyed public key from the KMS
const rekeyedPublicKey = await client.retrieveCoverCryptPublicMasterKey(publicKeyUID)

// updated policy is returned by the `rotateCoverCryptAttributes` but can also be fetch from the public key
const updatedPolicy = rekeyedPublicKey.policy()

// creating a new confidential marketing message
const confidentialMkgData = new TextEncoder().encode(
  "confidential_mkg_message"
)
encrypter = new CoverCryptHybridEncryption(updatedPolicy, rekeyedPublicKey)
const newConfidentialMkgCiphertext = encrypter.encrypt(
  "Department::MKG && Security Level::Confidential",
  confidentialMkgData
)

When using the KMS, the UID of the public key didn’t change. You can use it to encrypt with the updated policy.

const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

// creating a new confidential marketing message
const confidentialMkgData = new TextEncoder().encode(
  "confidential_mkg_message"
)
const newConfidentialMkgCiphertext = client.coverCryptEncrypt(
  publicKeyUID,
  "Department::MKG && Security Level::Confidential",
  confidentialMkgData
)
// retrieve the rekeyed public key from the KMS
PublicKey rekeyedPublicKey = kmsClient.retrieveCoverCryptPublicMasterKey(publicMasterKeyUniqueIdentifier);

// creating a new confidential marketing message
byte[] confidentialMkgData = "confidentialMkgMessage".getBytes(StandardCharsets.UTF_8);
String confidentialMkgEncryptionPolicy = "Department::MKG && Security Level::Confidential";
byte[] confidentialMkgCT = coverCrypt.encrypt(
    updatedPolicy,
    rekeyedPublicKey.bytes(),
    confidentialMkgEncryptionPolicy,
    confidentialMkgData);
confidential_mkg_data = b"confidential_secret_mkg_message"
confidential_mkg_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::MKG && Security Level::Confidential",
    public_key,
    confidential_mkg_data
)

decrypting the messages with the rekeyed key

The automatically rekeyed confidential marketing user key can still decrypt the “old” protected marketing message, as well as the new confidential marketing message.

const { CoverCryptHybridDecryption } = await CoverCrypt();

// retrieve the rekeyed user decryption key
const rekeyedMediumSecretMkgUserKey =
  await client.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid)

// protectedMkgCiphertext
const oldMediumSecretMkgCleartext = new CoverCryptHybridDecryption(
  rekeyedMediumSecretMkgUserKey
).decrypt(protectedMkgCiphertext)
assert(protectedMkgData, oldMediumSecretMkgCleartext)

// newConfidentialMkgCiphertext
const newConfidentialMkgCleartext = new CoverCryptHybridDecryption(
  rekeyedMediumSecretMkgUserKey
).decrypt(newConfidentialMkgCiphertext)
assert(confidentialMkgData, newConfidentialMkgCleartext)

The KMS has updated the user keys too, you can use the old UID to decrypt with the new policy.

const client = new KmsClient(new URL("http://localhost:9998/kmip/2_1"))

// protectedMkgCiphertext
const oldMediumSecretMkgCleartext = client.coverCryptDecrypt(mediumSecretMkgUserKeyUid, protectedMkgCiphertext)
assert(protectedMkgData, oldMediumSecretMkgCleartext)

// newConfidentialMkgCiphertext
const newConfidentialMkgCleartext = client.coverCryptDecrypt(mediumSecretMkgUserKeyUid, newConfidentialMkgCiphertext)
assert(confidentialMkgData, newConfidentialMkgCleartext)
// Retrieving the rekeyed `confidential marketing user` decryption key
PrivateKey rekeyedMediumSecretMkgUserKey =
    kmsClient.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid);

// Decrypting the "old" `protected marketing` message
DecryptedData protectedMkg__ = coverCrypt.decrypt(
    rekeyedMediumSecretMkgUserKey.bytes(),
    protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg__.getPlaintext());

// Decrypting the "new" `confidential marketing` message
DecryptedData confidentialMkg__ = coverCrypt.decrypt(
    rekeyedMediumSecretMkgUserKey.bytes(),
    confidentialMkgCT);
assert Arrays.equals(confidentialMkgData, confidentialMkg__.getPlaintext());
# decrypting the "old" `protected marketing` message
old_protected_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    confidential_mkg_userKey,
    protected_mkg_ciphertext
)
assert(old_protected_mkg_plaintext == protected_mkg_data)

# decrypting the "new" `confidential marketing` message
new_confidential_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    confidential_mkg_userKey,
    confidential_mkg_ciphertext
)
assert(new_confidential_mkg_plaintext == confidential_mkg_data)

decrypting the messages with the NON rekeyed key

However, the old, non-rekeyed confidential marketing user key can still decrypt the old protected marketing message but not the new confidential marketing message:

const { CoverCryptHybridDecryption } = await CoverCrypt();

// protectedMkgCiphertext
const plaintext_ = new CoverCryptHybridDecryption(
  oldConfidentialMkgUserKey
).decrypt(protectedMkgCiphertext)
assert(protectedMkgData, plaintext_)

// newConfidentialMkgCiphertext
try {
  // will throw
  new CoverCryptHybridDecryption(oldConfidentialMkgUserKey).decrypt(
    newConfidentialMkgCiphertext
  )
} catch (error) {
  // ==> the non rekeyed key cannot decrypt the new message after rotation
}
// Decrypting the "old" `protected marketing` message
DecryptedData protectedMkg___ = coverCrypt.decrypt(
    oldConfidentialMkgUserKey.bytes(),
    protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg___.getPlaintext());

// Decrypting the "new" `confidential marketing` message with the old key fails
try {
    DecryptedData confidentialMkg___ = coverCrypt.decrypt(
        oldConfidentialMkgUserKey.bytes(),
        confidentialMkgCT);
    assert Arrays.equals(confidentialMkgData, confidentialMkg___.getPlaintext());
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}
# decrypting the "old" `protected marketing` message with the old key works
old_protected_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    old_confidential_mkg_userKey,
    protected_mkg_ciphertext
)
assert(old_protected_mkg_plaintext == protected_mkg_data)

# decrypting the "new" `confidential marketing` message with the old key fails
try:
    new_confidential_mkg_plaintext, _ = CoverCryptInstance.decrypt(
        old_confidential_mkg_userKey,
        confidential_mkg_ciphertext
    )
except Exception as e:
    # ==> the user is not be able to decrypt

The whole code

The whole code in a single blob of the steps above

If you want to see full code of usage of cloudproof_js, please check the examples directory in Github.

// Access to the KMS server.
// Change the Cosmian Server Server URL and API key as appropriate
final KmsClient kmsClient = new KmsClient("http://localhost:9998", Optional.empty());

// Direct access to the native library (used with attributes rotation below)
final CoverCrypt coverCrypt = new CoverCrypt();

// Instantiate a policy; see comments in the policy() method for details
Policy policy = policy();

String[] ids = kmsClient.createCoverCryptMasterKeyPair(policy);
String privateMasterKeyUniqueIdentifier = ids[0];
String publicMasterKeyUniqueIdentifier = ids[1];

// Master Keys can be exported from the KMS
// export the private master key
// PrivateKey privateMasterKey = kmsClient.retrieveCoverCryptPrivateMasterKey(privateMasterKeyUniqueIdentifier);
// byte[] _privateMasterKeyBytes = privateMasterKey.bytes();
// export the public key
// PublicKey publicKey = kmsClient.retrieveCoverCryptPublicMasterKey(publicMasterKeyUniqueIdentifier);
// byte[] _publicKeyBytes = publicKey.bytes();

byte[] protectedMkgData = "protectedMkgMessage".getBytes(StandardCharsets.UTF_8);
String protectedMkgEncryptionPolicy = "Department::MKG && Security Level::Protected";
byte[] protectedMkgCT = kmsClient.coverCryptEncrypt(
    publicMasterKeyUniqueIdentifier,
    protectedMkgData,
    protectedMkgEncryptionPolicy);

byte[] topSecretMkgData = "topSecretMkgMessage".getBytes(StandardCharsets.UTF_8);
String topSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Top Secret";
byte[] topSecretMkgCT = kmsClient.coverCryptEncrypt(
    publicMasterKeyUniqueIdentifier,
    topSecretMkgData,
    topSecretMkgEncryptionPolicy);

byte[] protectedFinData = "protectedFinMessage".getBytes(StandardCharsets.UTF_8);
String protectedFinEncryptionPolicy = "Department::FIN && Security Level::Protected";
byte[] protectedFinCT = kmsClient.coverCryptEncrypt(
    publicMasterKeyUniqueIdentifier,
    protectedFinData,
    protectedFinEncryptionPolicy);

// the confidential marketing use
String confidentialMkgUserKeyUid = kmsClient.createCoverCryptUserDecryptionKey(
    "Department::MKG && Security Level::Confidential",
    privateMasterKeyUniqueIdentifier);

// the top secret marketing financial user
String topSecretMkgFinUserKeyUid = kmsClient.createCoverCryptUserDecryptionKey(
    "(Department::MKG || Department::FIN) && Security Level::Top Secret",
    privateMasterKeyUniqueIdentifier);

// as with the master keys, the user keys can be exported to be used with the
// native library
// PrivateKey confidentialMkgUserKey_ =
// kmsClient.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid);
// PrivateKey topSecretMkgFinUserKey = kmsClient.retrieveCoverCryptUserDecryptionKey(topSecretMkgFinUserKeyUid);

// The confidential marketing user can successfully decrypt a low-security
// marketing message
DecryptedData protectedMkg = kmsClient.coverCryptDecrypt(confidentialMkgUserKeyUid, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg.getPlaintext());

// ... however, it can neither decrypt a marketing message with higher security:
try {
    kmsClient.coverCryptDecrypt(confidentialMkgUserKeyUid, topSecretMkgCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}

// ... nor decrypt a message from another department even with a lower security:
try {
    kmsClient.coverCryptDecrypt(confidentialMkgUserKeyUid, protectedFinCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}

// As expected, the top-secret marketing financial user can successfully decrypt
// all messages
DecryptedData protectedMkg_ = kmsClient.coverCryptDecrypt(topSecretMkgFinUserKeyUid, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg_.getPlaintext());

DecryptedData topSecretMkg_ = kmsClient.coverCryptDecrypt(topSecretMkgFinUserKeyUid, topSecretMkgCT);
assert Arrays.equals(topSecretMkgData, topSecretMkg_.getPlaintext());

DecryptedData protectedFin_ = kmsClient.coverCryptDecrypt(topSecretMkgFinUserKeyUid, protectedFinCT);
assert Arrays.equals(protectedFinData, protectedFin_.getPlaintext());

// -------------------------------------------
// Attributes rotation
// -------------------------------------------

// Before rotating attributes, let us make a local copy of the current
// `confidential marketing` user to show
// what happens to non-refreshed keys after the attribute rotation.
PrivateKey oldConfidentialMkgUserKey = kmsClient.retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid);

// Now rotate the MKG attribute - all active keys will be rekeyed
kmsClient.rotateCoverCryptAttributes(privateMasterKeyUniqueIdentifier,
    new Attr[] {new Attr("Department", "MKG")});

// Retrieve the rekeyed public key from the KMS
PublicKey rekeyedPublicKey = kmsClient.retrieveCoverCryptPublicMasterKey(publicMasterKeyUniqueIdentifier);
// Retrieve the updated policy
Policy updatedPolicy = Policy.fromAttributes(rekeyedPublicKey.attributes());

// Creating a new `confidential marketing` message
byte[] confidentialMkgData = "confidentialMkgMessage".getBytes(StandardCharsets.UTF_8);
String confidentialMkgEncryptionPolicy = "Department::MKG && Security Level::Confidential";
byte[] confidentialMkgCT = coverCrypt.encrypt(
    updatedPolicy,
    rekeyedPublicKey.bytes(),
    confidentialMkgEncryptionPolicy,
    confidentialMkgData);

// Decrypting the messages with the rekeyed key
// The automatically rekeyed confidential marketing user key can still decrypt
// the “old” protected marketing
// message, as well as the new confidential marketing message.

// Retrieving the rekeyed `confidential marketing user` decryption key
PrivateKey rekeyedConfidentialMkgUserKey = kmsClient
    .retrieveCoverCryptUserDecryptionKey(confidentialMkgUserKeyUid);
assert !Arrays.equals(oldConfidentialMkgUserKey.bytes(), rekeyedConfidentialMkgUserKey.bytes());

// Decrypting the "old" `protected marketing` message
DecryptedData protectedMkg__ = coverCrypt.decrypt(
    rekeyedConfidentialMkgUserKey.bytes(),
    protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg__.getPlaintext());

// Decrypting the "new" `confidential marketing` message
DecryptedData confidentialMkg__ = coverCrypt.decrypt(
    rekeyedConfidentialMkgUserKey.bytes(),
    confidentialMkgCT);
assert Arrays.equals(confidentialMkgData, confidentialMkg__.getPlaintext());

// Decrypting the messages with the NON rekeyed key
// However, the old, non-rekeyed confidential marketing user key can still
// decrypt the old protected marketing
// message but not the new confidential marketing message:

// Decrypting the "old" `protected marketing` message
DecryptedData protectedMkg___ = coverCrypt.decrypt(
    oldConfidentialMkgUserKey.bytes(),
    protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg___.getPlaintext());

// Decrypting the "new" `confidential marketing` message with the old key fails
try {
    DecryptedData confidentialMkg___ = coverCrypt.decrypt(
        oldConfidentialMkgUserKey.bytes(),
        confidentialMkgCT);
    assert Arrays.equals(confidentialMkgData, confidentialMkg___.getPlaintext());
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}

See the Java KMS code for attributes rotation

// Direct access to the native library
final CoverCrypt coverCrypt = new CoverCrypt();

// Instantiate a policy; see comments in the policy() method for details
Policy policy = policy();

MasterKeys masterKeys = coverCrypt.generateMasterKeys(policy);
byte[] privateMasterKeyBytes = masterKeys.getPrivateKey();
byte[] publicKeyBytes = masterKeys.getPublicKey();

byte[] protectedMkgData = "protectedMkgMessage".getBytes(StandardCharsets.UTF_8);
String protectedMkgEncryptionPolicy = "Department::MKG && Security Level::Protected";
byte[] protectedMkgCT = coverCrypt.encrypt(
    policy,
    publicKeyBytes,
    protectedMkgEncryptionPolicy,
    protectedMkgData);

byte[] topSecretMkgData = "topSecretMkgMessage".getBytes(StandardCharsets.UTF_8);
String topSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Top Secret";
byte[] topSecretMkgCT = coverCrypt.encrypt(
    policy,
    publicKeyBytes,
    topSecretMkgEncryptionPolicy,
    topSecretMkgData);

byte[] protectedFinData = "protectedFinMessage".getBytes(StandardCharsets.UTF_8);
String protectedFinEncryptionPolicy = "Department::FIN && Security Level::Protected";
byte[] protectedFinCT = coverCrypt.encrypt(
    policy,
    publicKeyBytes,
    protectedFinEncryptionPolicy,
    protectedFinData);

// the confidential marketing use
byte[] confidentialMkgUserKey = coverCrypt.generateUserPrivateKey(
    privateMasterKeyBytes,
    "Department::MKG && Security Level::Confidential",
    policy);

// the top secret marketing financial user
byte[] topSecretMkgFinUserKeyUid = coverCrypt.generateUserPrivateKey(
    privateMasterKeyBytes,
    "(Department::MKG || Department::FIN) && Security Level::Top Secret",
    policy);

// The confidential marketing user can successfully decrypt a low-security marketing message
DecryptedData protectedMkg = coverCrypt.decrypt(confidentialMkgUserKey, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg.getPlaintext());

// ... however, it can neither decrypt a marketing message with higher security:
try {
    coverCrypt.decrypt(confidentialMkgUserKey, topSecretMkgCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}

// ... nor decrypt a message from another department even with a lower security:
try {
    coverCrypt.decrypt(confidentialMkgUserKey, protectedFinCT);
    throw new RuntimeException("the message should not be decrypted!");
} catch (CloudproofException e) {
    // ==> fine, the user is not able to decrypt
}

// As expected, the top-secret marketing financial user can successfully decrypt all messages
DecryptedData protectedMkg_ = coverCrypt.decrypt(topSecretMkgFinUserKeyUid, protectedMkgCT);
assert Arrays.equals(protectedMkgData, protectedMkg_.getPlaintext());

DecryptedData topSecretMkg = coverCrypt.decrypt(topSecretMkgFinUserKeyUid, topSecretMkgCT);
assert Arrays.equals(topSecretMkgData, topSecretMkg.getPlaintext());

DecryptedData protectedFin = coverCrypt.decrypt(topSecretMkgFinUserKeyUid, protectedFinCT);
assert Arrays.equals(protectedFinData, protectedFin.getPlaintext());
from cloudproof_py.cover_crypt import Policy, PolicyAxis, Attribute, CoverCrypt

"""
Creating Policy
"""

policy = Policy()
policy.add_axis(
    PolicyAxis(
        "Security Level",
        ["Protected", "Confidential", "Top Secret"],
        hierarchical=True,
    )
)
policy.add_axis(
    PolicyAxis("Department", ["FIN", "MKG", "HR"], hierarchical=False)
)
print(policy)

"""
Generating master keys
"""

CoverCryptInstance = CoverCrypt()
master_private_key, public_key = CoverCryptInstance.generate_master_keys(policy)

"""
Messages encryption
"""

protected_mkg_data = b"protected_mkg_message"
protected_mkg_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::MKG && Security Level::Protected",
    public_key,
    protected_mkg_data
)

topSecret_mkg_data = b"top_secret_mkg_message"
topSecret_mkg_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::MKG && Security Level::Top Secret",
    public_key,
    topSecret_mkg_data
)

protected_fin_data = b"protected_fin_message"
protected_fin_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::FIN && Security Level::Protected",
    public_key,
    protected_fin_data
)

"""
Generating user keys
"""

confidential_mkg_userKey = CoverCryptInstance.generate_user_secret_key(
    master_private_key,
    "Department::MKG && Security Level::Confidential",
    policy
)

topSecret_mkg_fin_userKey = CoverCryptInstance.generate_user_secret_key(
    master_private_key,
    "(Department::MKG || Department::FIN) && Security Level::Top Secret",
    policy
)

"""
Decryption with the right access policy
"""

protected_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    confidential_mkg_userKey,
    protected_mkg_ciphertext
)
assert(protected_mkg_plaintext == protected_mkg_data)

"""
Decryption without the right access will fail
"""

try:
    # will throw
    CoverCryptInstance.decrypt(confidential_mkg_userKey, topSecret_mkg_ciphertext)
except Exception as e:
    # ==> the user is not be able to decrypt
    print(e)

try:
    # will throw
    CoverCryptInstance.decrypt(confidential_mkg_userKey, protected_fin_ciphertext)
except Exception as e:
    # ==> the user is not be able to decrypt
    print(e)

"""
User with Top Secret access can decrypt messages of all Security Level within the right Department
"""

protected_mkg_plaintext2, _ = CoverCryptInstance.decrypt(
    topSecret_mkg_fin_userKey,
    protected_mkg_ciphertext
)
assert(protected_mkg_plaintext2 == protected_mkg_data)

topSecret_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    topSecret_mkg_fin_userKey,
    topSecret_mkg_ciphertext
)
assert(topSecret_mkg_plaintext == topSecret_mkg_data)

protected_fin_plaintext, _ = CoverCryptInstance.decrypt(
    topSecret_mkg_fin_userKey,
    protected_fin_ciphertext
)
assert(protected_fin_plaintext == protected_fin_data)

"""
Rotating Attributes
"""

# make a copy of the current user key
old_confidential_mkg_userKey = confidential_mkg_userKey.deep_copy()

# rotate MKG attribute
policy.rotate(Attribute("Department", "MKG"))

# update master keys
CoverCryptInstance.update_master_keys(policy, master_private_key, public_key)

# update user key
CoverCryptInstance.refresh_user_secret_key(
    confidential_mkg_userKey,
    "Department::MKG && Security Level::Confidential",
    master_private_key,
    policy,
    keep_old_accesses=True
)

"""
New confidential marketing message
"""

confidential_mkg_data = b"confidential_secret_mkg_message"
confidential_mkg_ciphertext = CoverCryptInstance.encrypt(
    policy, "Department::MKG && Security Level::Confidential",
    public_key,
    confidential_mkg_data
)

"""
Decrypting the messages with the rekeyed key
"""

# decrypting the "old" `protected marketing` message
old_protected_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    confidential_mkg_userKey,
    protected_mkg_ciphertext
)
assert(old_protected_mkg_plaintext == protected_mkg_data)

# decrypting the "new" `confidential marketing` message
new_confidential_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    confidential_mkg_userKey,
    confidential_mkg_ciphertext
)
assert(new_confidential_mkg_plaintext == confidential_mkg_data)

# Decrypting the messages with the NON rekeyed key

# decrypting the "old" `protected marketing` message with the old key works
old_protected_mkg_plaintext, _ = CoverCryptInstance.decrypt(
    old_confidential_mkg_userKey,
    protected_mkg_ciphertext
)
assert(old_protected_mkg_plaintext == protected_mkg_data)

# decrypting the "new" `confidential marketing` message with the old key fails
try:
    new_confidential_mkg_plaintext, _ = CoverCryptInstance.decrypt(
        old_confidential_mkg_userKey,
        confidential_mkg_ciphertext
    )
except Exception as e:
    # ==> the user is not be able to decrypt
    print(e)

© Copyright 2018-2022 Cosmian. All rights reserved