Attributes encryption
Cloudproof Encryption provides libraries and tools to encrypt and securely index large repositories of data - Big Data - with high performance and advanced security primitives.
See the use cases and benefits and a description of the cryptosystems used.
The libraries are available in multiple languages facilitating encryption close to the data source and decryption close to the decryption target, including mobile devices and browsers.
This section describes the Attributes Encryption API, the Searchable Encryption API is on this page
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
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>2.0.0</version>
<type>jar</type>
</dependency>
Encryption and decryption can be accomplished in the KMS, however it is likely that you will want to perform them locally.
This is accomplished using the native library, compiled from Rust.
The cloudproof_java
uses Java Native Access to call the native library.
Please see the CoverCrypt project on how build the library. In your java project, the library needs to be placed inside in
src/main/resources/linux-x86-64
folder for a Linux Intel machinesrc/main/resources/linux-amd64
folder for a Linux AMD machinesrc/main/resources/darwin
folder for a Mac running MacOSsrc/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.
Coming soon!
Creating a policy¶
A Policy is specified by Policy Axes, defining a 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 the example below, we create a Policy which combines two axes, a
security level
axis and a department
axis. 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 policy = new Policy(Integer.MAX_VALUE)
// 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",
"Low Secret",
"Medium Secret",
"High Secret",
"Top Secret"
},
true) // <- hierarchical axis
.addAxis("Department",
new String[] {
"R&D",
"HR",
"MKG",
"FIN" },
false); // <- non hierarchical axis
Coming soon!
Security Level Axis¶
The first Policy Axis is the ‘Security Level’ axis and is a
hierarchical axis made of 5 levels: Protected, Low Secret, ..., Top Secret
.
It is hierarchical: a user being granted access to level n
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 4 values: R&D, HR, MKG, 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.
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.
To generate keys you need access to a Cosmian KMS server and, unless you run in dev mode, an API Key to authenticate to the server.
const client = new KmipClient(new URL("http://localhost:9998/kmip/2_1"))
// create master keys
const [privateMasterKeyUID, publicKeyUID] =
await client.createAbeMasterKeyPair(policy)
// fetch the keys from the KMS
const privateMasterKey = await client.retrieveAbePrivateMasterKey(
privateMasterKeyUID
)
// eslint-disable-next-line no-unused-vars
const privateMasterKeyBytes = privateMasterKey.bytes()
const publicKey = await client.retrieveAbePublicMasterKey(publicKeyUID)
const publicKeyBytes = publicKey.bytes()
Keys can also be generated locally using the WASM code
To generate keys you need access to a Cosmian KMS server and, unless you run in dev mode, an API Key to authenticate to the server.
Abe client = new Abe(
new RestClient([KMS_SERVER_URL], [YOUR_API_KEY])
);
// create the Master Keys
String[] ids = client.createMasterKeyPair(policy);
// recover the Keys
String privateMasterKeyUID = ids[0];
PrivateKey privateMasterKey = client.retrievePrivateMasterKey(privateMasterKeyUID);
byte[] privateMasterKeyBytes = privateMasterKey.bytes();
String publicKeyUID = ids[1];
PrivateKey publicKey = client.retrievePublicMasterKey(publicMasterKeyUID);
byte[] publicKeyBytes = publicKey.bytes();
static final FfiWrapper INSTANCE = (FfiWrapper) Native.load("cosmian_cover_crypt", FfiWrapper.class);
static final Ffi ffi = new Ffi(INSTANCE, new Specifications(Implementation.CoverCrypt));
MasterKeys masterKeys = ffi.generateMasterKeys(policy);
byte[] privateMasterKeyBytes = masterKeys.getPrivateKey()
byte[] publicKeyBytes = masterKeys.getPublicKey()
Coming soon!
Encrypting Data¶
Data is encrypted using the Master Authority Public Key and at least one attribute from each Policy axis.
Anyone who has access to the Public Key, can encrypt data, however, only users possessing user keys with the right access policy can decrypt data.
This shows the encryption of 3 messages with different attributes.
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 the CoverCryptHybridEncryption
class
a low secret marketing message¶
const { CoverCryptHybridEncryption } = await CoverCrypt();
const lowSecretMkgData = new TextEncoder().encode("low_secret_mkg_message")
// The constructor also accepts the public key object returned by the KMS
let encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const lowSecretMkgCiphertext = encrypter.encrypt(
"Department::MKG && Security Level::Low Secret",
lowSecretMkgData
)
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 low secret finance message¶
const { CoverCryptHybridEncryption } = await CoverCrypt();
const lowSecretFinData = new TextEncoder().encode("low_secret_fin_message")
encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const lowSecretFinCiphertext = encrypter.encrypt(
"Department::FIN && Security Level::Low Secret",
lowSecretFinData
)
Encrypting using the native library is fast and provides many options
a low secret marketing message¶
byte[] lowSecretMkgData = "low_secret_mkg_message".getBytes(StandardCharsets.UTF_8);
String lowSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Low Secret";
byte[] lowSecretMkgCiphertext = ffi.encrypt(
policy, masterKeys.getPublicKey(),
lowSecretMkgEncryptionPolicy, lowSecretMkgData
);
a top secret marketing message¶
byte[] topSecretMkgData = "top_secret_mkg_message".getBytes(StandardCharsets.UTF_8);
String topSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Top Secret";
byte[] topSecretMkgCiphertext = ffi.encrypt(
policy, masterKeys.getPublicKey(),
topSecretMkgEncryptionPolicy, topSecretMkgData
);
a low secret finance message¶
byte[] lowSecretFinData = "low_secret_fin_message".getBytes(StandardCharsets.UTF_8);
String lowSecretFinEncryptionPolicy = "Department::FIN && Security Level::Low Secret";
byte[] lowSecretFinCiphertext = ffi.encrypt(
policy, masterKeys.getPublicKey(),
lowSecretFinEncryptionPolicy, lowSecretFinData
);
Coming soon!
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 their different access policies to illustrate their effect.
the medium secret marketing user¶
This user can decrypt messages from the marketing department only with a security level of Medium Secret or below:
const mediumSecretMkgAccess =
"Department::MKG && Security Level::Medium Secret"
const mediumSecretMkgUserKeyUid = await client.createAbeUserDecryptionKey(
mediumSecretMkgAccess,
privateMasterKeyUID
)
const mediumSecretMkgUserKey = await client.retrieveAbeUserDecryptionKey(
mediumSecretMkgUserKeyUid
)
const mediumSecretMkgUserKeyBytes = mediumSecretMkgUserKey.bytes()
the top secret marketing financial user¶
This user can decrypt messages from the marketing department OR the financial department that have a security level of Top Secret or below
const topSecretMkgFinAccess =
"(Department::MKG || Department::FIN) && Security Level::Top Secret"
const topSecretMkgFinUserKeyUid = await client.createAbeUserDecryptionKey(
topSecretMkgFinAccess,
privateMasterKeyUID
)
const topSecretMkgFinUserKey = await client.retrieveAbeUserDecryptionKey(
topSecretMkgFinUserKeyUid
)
const topSecretMkgFinUserKeyBytes = topSecretMkgFinUserKey.bytes()
the top secret - only - financial user¶
This user can decrypt messages from the financial department that have a security level of Top Secret or below
const topSecretFinAccess = "(Department::FIN) && Security Level::Top Secret"
const topSecretFinUserKeyUid = await client.createAbeUserDecryptionKey(
topSecretFinAccess,
privateMasterKeyUID
)
const topSecretFinUserKey = await client.retrieveAbeUserDecryptionKey(
topSecretFinUserKeyUid
)
// eslint-disable-next-line no-unused-vars
const topSecretFinUserKeyBytes = topSecretFinUserKey.bytes()
User Decryption Keys can also be generated calling the local Web Assembly
the medium secret marketing user¶
This user can decrypt messages from the marketing department only with a security level of Medium Secret or below:
const { CoverCryptKeyGeneration } = await CoverCrypt();
const keygen = new CoverCryptKeyGeneration()
const mediumSecretMkgUserKeyBytes =
keygen.generateUserSecretKey(
masterSecretKeyBytes,
"Department::MKG && Security Level::Medium Secret",
policy,
)
the top secret marketing financial user¶
This user can decrypt messages from the marketing department OR the financial department that have a security level of Top Secret or below
the medium secret marketing user¶
This user can decrypt messages from the marketing department only with a security level of Medium Secret or below:
AccessPolicy mediumSecretMkgAccess = new And(
new Attr("Department", "MKG"),
new Attr("Security Level", "Medium Secret"),
);
String mediumSecretMkgUserKeyUid =
client.createUserDecryptionKey(
mediumSecretMkgAccess,
privateMasterKeyUID,
);
PrivateKey mediumSecretMkgUserKey = client.retrieveUserDecryptionKey(mediumSecretMkgUserKeyUid);
the top secret marketing financial user¶
This user can decrypt messages from the marketing department OR the financial department that have a security level of Top Secret or below
AccessPolicy topSecretMkgFinAccess =
new And(
new Or(new Attr("Department", "MKG"), new Attr("Department", "FIN")),
new Attr("Security Level", "Top Secret"),
);
String topSecretMkgFinUserKeyUid =
client.createUserDecryptionKey(
topSecretMkgFinAccess,
privateMasterKeyUID,
);
PrivateKey topSecretMkgFinUserKey = client.retrieveUserDecryptionKey(topSecretMkgFinUserKeyUid);
User keys can be locally generated using the native library
the medium secret marketing user¶
This user can decrypt messages from the marketing department only with a security level of Medium Secret or below:
AccessPolicy mediumSecretMkgAccess = new And(
new Attr("Department", "MKG"),
new Attr("Security Level", "Medium Secret"),
);
byte[] mediumSecretMkgUserKeyBytes =
ffi.generateUserPrivateKey(
privateMasterKeyBytes,
mediumSecretMkgAccess,
policy,
);
the top secret marketing financial user¶
This user can decrypt messages from the marketing department OR the financial department that have a security level of Top Secret or below
Coming soon!
Decrypting Ciphertexts¶
The medium secret marketing user can successfully decrypt a low security marketing message:
const { CoverCryptHybridDecryption } = await CoverCrypt();
// note: the constructor also accepts the private key object returned by the KMS
const lowSecretMkgCleartext = new CoverCryptHybridDecryption(
mediumSecretMkgUserKeyBytes
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgCleartext, lowSecretMkgData)
Coming soon!
.. however it can neither decrypt a marketing message with higher security:
Coming soon!
… nor decrypt a message from another department even with a lower security:
Coming soon!
As expected, the top secret marketing financial user can successfully decrypt all messages
const { CoverCryptHybridDecryption } = await CoverCrypt();
// lowSecretMkgCiphertext
const lowSecretMkgCleartext2 = new CoverCryptHybridDecryption(
topSecretMkgFinUserKeyBytes
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgData, lowSecretMkgCleartext2)
// lowSecretFinCiphertext
const topSecretMkgCleartext = new CoverCryptHybridDecryption(
topSecretMkgFinUserKeyBytes
).decrypt(topSecretMkgCiphertext)
assert(topSecretMkgData, topSecretMkgCleartext)
// lowSecretFinCiphertext
const lowSecretFinCleartext = new CoverCryptHybridDecryption(
topSecretMkgFinUserKeyBytes
).decrypt(lowSecretFinCiphertext)
assert(lowSecretFinData, lowSecretFinCleartext)
// lowSecretMkgCiphertext
byte[] data = ffi.decrypt(
top_secret_mkg_fin_user_key.bytes(),
lowSecretMkgCiphertext
);
assertArrayEquals(
lowSecretMkgData,
data
);
// topSecretMkgCiphertext
byte[] data = ffi.decrypt(
top_secret_mkg_fin_user_key.bytes(),
topSecretMkgCiphertext
);
assertArrayEquals(
topSecretMkgData,
data
);
// lowSecretFinCiphertext
byte[] data = ffi.decrypt(
top_secret_mkg_fin_user_key.bytes(),
lowSecretFinCiphertext
);
assertArrayEquals(
lowSecretFinData,
data
);
Coming soon!
Rotating Attributes¶
At anytime the Master Authority can rotate an attribute.
When that happens future encryption of data for a given attribute cannot be decrypted with keys which are not “refreshed” for that attribute.
We are going to rotate the Department::MKG attribute.
As long as a key is active in the KMS (the key has not been revoked), it will be automatically rekeyed when an attribute is rotated.
rotating the Department::MKG attribute¶
Before rotating attributes, let us make a local copy of the
current medium secret marketing user
to show what happens to non-refreshed keys after
the attribute rotation.
// retrieve the key
const originalMediumSecretMkgUserKey =
await client.retrieveAbeUserDecryptionKey(mediumSecretMkgUserKeyUid)
// Now revoke the MKG attribute - all active keys will be rekeyed
client.rotateAbeAttributes(privateMasterKeyUID, ["Department::MKG"])
// retrieve the rekeyed public key
const rekeyedPublicKey = await client.retrieveAbePublicMasterKey(publicKeyUID)
// retrieve the rekeyed user decryption key
const rekeyedMediumSecretMkgUserKey =
await client.retrieveAbeUserDecryptionKey(mediumSecretMkgUserKeyUid)
// retrieve the key
PrivateKey originalMediumSecretMkgUserKey =
client.retrieveUserDecryptionKey(mediumSecretMkgUserKeyUid);
// Now rotate the MKG attribute - all active keys will be rekeyed
client.rotateAttributes(
privateMasterKeyUID,
new Attr[] { new Attr("Department", "MKG") }
);
// retrieve the rekeyed public key
PrivateKey rekeyedPublicKey =
client.retrievePublicMasterKey(publicKeyUID);
// retrieve the rekeyed user decryption key
PrivateKey rekeyedMediumSecretMkgUserKey =
client.retrieveUserDecryptionKey(mediumSecretMkgUserKeyUid);
Coming soon!
creating a new medium secret marketing message¶
const { CoverCryptHybridEncryption } = await CoverCrypt();
const mediumSecretMkgData = new TextEncoder().encode(
"medium_secret_mkg_message"
)
encrypter = new CoverCryptHybridEncryption(policy, rekeyedPublicKey)
const newMediumSecretMkgCiphertext = encrypter.encrypt(
"Department::MKG && Security Level::Medium Secret",
mediumSecretMkgData
)
byte[] mediumSecretMkgData = "medium_secret_mkg_message".getBytes(StandardCharsets.UTF_8);
Attr[] mediumSecretMkgEncryptionPolicy = "Department::MKG && Security Level::Medium Secret")
};
byte[] mediumSecretMkgCT = ffi.encrypt(
policy, rekeyedPublicKey.bytes(),
mediumSecretMkgEncryptionPolicy, mediumSecretMkgData
);
Coming soon!
decrypting the messages with the rekeyed key¶
The automatically rekeyed medium secret marketing user key can still decrypt the “old” low secret marketing message, as well as the new medium secret marketing message.
const { CoverCryptHybridDecryption } = await CoverCrypt();
// lowSecretMkgCiphertext
const oldMediumSecretMkgCleartext = new CoverCryptHybridDecryption(
rekeyedMediumSecretMkgUserKey
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgData, oldMediumSecretMkgCleartext)
// newMediumSecretMkgCiphertext
const newMediumSecretMkgCleartext = new CoverCryptHybridDecryption(
rekeyedMediumSecretMkgUserKey
).decrypt(newMediumSecretMkgCiphertext)
assert(mediumSecretMkgData, newMediumSecretMkgCleartext)
// lowSecretMkgCT
byte[] data = ffi.decrypt(
rekeyedMediumSecretMkgUserKey.bytes(),
lowSecretMkgCT
);
assertArrayEquals(
lowSecretMkgData,
data
);
// mediumSecretMkgCT
byte[] data = ffi.decrypt(
rekeyedMediumSecretMkgUserKey.bytes(),
mediumSecretMkgCT
);
assertArrayEquals(
mediumSecretMkgData,
data
);
Coming soon!
decrypting the messages with the NON rekeyed key¶
However, the old, non rekeyed medium secret marketing user key can still decrypt the old low secret marketing message but not the new medium secret marketing message:
const { CoverCryptHybridDecryption } = await CoverCrypt();
// lowSecretMkgCiphertext
const plaintext_ = new CoverCryptHybridDecryption(
originalMediumSecretMkgUserKey
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgData, plaintext_)
// newMediumSecretMkgCiphertext
try {
// will throw
new CoverCryptHybridDecryption(originalMediumSecretMkgUserKey).decrypt(
newMediumSecretMkgCiphertext
)
} catch (error) {
// ==> the non rekeyed key cannot decrypt the new message after rotation
}
// lowSecretMkgCT
byte[] data = ffi.decrypt(
originalMediumSecretMkgUserKey.bytes(),
lowSecretMkgCT
);
assertArrayEquals(
lowSecretMkgData,
data
);
// mediumSecretMkgCT
try {
// will throw
ffi.decrypt(
originalMediumSecretMkgUserKey.bytes(),
mediumSecretMkgCT
);
} catch (CosmianException e) {
// ==> the non rekeyed key cannot decrypt the new message after rotation
}
Coming soon!
All code¶
import { CoverCrypt, KmipClient, Policy, PolicyAxis } from "cloudproof_js"
const assert = (x, y) => {
if (new TextDecoder().decode(x) !== new TextDecoder().decode(y))
throw new Error("Items MUST be equal (left: " + x + " right: " + y + ")")
}
//
// Creating a policy
//
const policy = new Policy([
new PolicyAxis("Department", ["R&D", "HR", "FIN", "MKG"], false),
new PolicyAxis(
"Security Level",
["Protected", "Low Secret", "Medium Secret", "High Secret", "Top Secret"],
true
)
])
;(async () => {
const client = new KmipClient(new URL("http://localhost:9998/kmip/2_1"))
//
// Generating the master keys
//
// create master keys
const [privateMasterKeyUID, publicKeyUID] =
await client.createAbeMasterKeyPair(policy)
// fetch the keys from the KMS
const privateMasterKey = await client.retrieveAbePrivateMasterKey(
privateMasterKeyUID
)
// eslint-disable-next-line no-unused-vars
const privateMasterKeyBytes = privateMasterKey.bytes()
const publicKey = await client.retrieveAbePublicMasterKey(publicKeyUID)
const publicKeyBytes = publicKey.bytes()
//
// Encrypting Data
//
const { CoverCryptHybridDecryption, CoverCryptHybridEncryption } =
await CoverCrypt()
// a low secret marketing message
const lowSecretMkgData = new TextEncoder().encode("low_secret_mkg_message")
// The constructor also accepts the public key object returned by the KMS
let encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const lowSecretMkgCiphertext = encrypter.encrypt(
"Department::MKG && Security Level::Low Secret",
lowSecretMkgData
)
// a top secret marketing message
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 low secret finance message
const lowSecretFinData = new TextEncoder().encode("low_secret_fin_message")
encrypter = new CoverCryptHybridEncryption(policy, publicKeyBytes)
const lowSecretFinCiphertext = encrypter.encrypt(
"Department::FIN && Security Level::Low Secret",
lowSecretFinData
)
//
// Generating User Decryption Keys
//
// the medium secret marketing user
const mediumSecretMkgAccess =
"Department::MKG && Security Level::Medium Secret"
const mediumSecretMkgUserKeyUid = await client.createAbeUserDecryptionKey(
mediumSecretMkgAccess,
privateMasterKeyUID
)
const mediumSecretMkgUserKey = await client.retrieveAbeUserDecryptionKey(
mediumSecretMkgUserKeyUid
)
const mediumSecretMkgUserKeyBytes = mediumSecretMkgUserKey.bytes()
// the top secret marketing financial user
const topSecretMkgFinAccess =
"(Department::MKG || Department::FIN) && Security Level::Top Secret"
const topSecretMkgFinUserKeyUid = await client.createAbeUserDecryptionKey(
topSecretMkgFinAccess,
privateMasterKeyUID
)
const topSecretMkgFinUserKey = await client.retrieveAbeUserDecryptionKey(
topSecretMkgFinUserKeyUid
)
const topSecretMkgFinUserKeyBytes = topSecretMkgFinUserKey.bytes()
// the top secret financial user
const topSecretFinAccess = "(Department::FIN) && Security Level::Top Secret"
const topSecretFinUserKeyUid = await client.createAbeUserDecryptionKey(
topSecretFinAccess,
privateMasterKeyUID
)
const topSecretFinUserKey = await client.retrieveAbeUserDecryptionKey(
topSecretFinUserKeyUid
)
// eslint-disable-next-line no-unused-vars
const topSecretFinUserKeyBytes = topSecretFinUserKey.bytes()
//
// Decrypting Ciphertexts
//
// note: the constructor also accepts the private key object returned by the KMS
const lowSecretMkgCleartext = new CoverCryptHybridDecryption(
mediumSecretMkgUserKeyBytes
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgCleartext, lowSecretMkgData)
// .. however it can neither decrypt a marketing message with higher security:
try {
// will throw
new CoverCryptHybridDecryption(mediumSecretMkgUserKey).decrypt(
topSecretMkgCiphertext
)
} catch (error) {
// ==> the user is not be able to decrypt
}
// ... nor decrypt a message from another department even with a lower security:
try {
// will throw
new CoverCryptHybridDecryption(topSecretFinUserKey).decrypt(
lowSecretMkgCiphertext
)
} catch (error) {
// ==> the user is not be able to decrypt
}
// lowSecretMkgCiphertext
const lowSecretMkgCleartext2 = new CoverCryptHybridDecryption(
topSecretMkgFinUserKeyBytes
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgData, lowSecretMkgCleartext2)
// lowSecretFinCiphertext
const topSecretMkgCleartext = new CoverCryptHybridDecryption(
topSecretMkgFinUserKeyBytes
).decrypt(topSecretMkgCiphertext)
assert(topSecretMkgData, topSecretMkgCleartext)
// lowSecretFinCiphertext
const lowSecretFinCleartext = new CoverCryptHybridDecryption(
topSecretMkgFinUserKeyBytes
).decrypt(lowSecretFinCiphertext)
assert(lowSecretFinData, lowSecretFinCleartext)
//
// Rotating Attributes
//
// retrieve the key
const originalMediumSecretMkgUserKey =
await client.retrieveAbeUserDecryptionKey(mediumSecretMkgUserKeyUid)
// Now revoke the MKG attribute - all active keys will be rekeyed
client.rotateAbeAttributes(privateMasterKeyUID, ["Department::MKG"])
// retrieve the rekeyed public key
const rekeyedPublicKey = await client.retrieveAbePublicMasterKey(publicKeyUID)
// retrieve the rekeyed user decryption key
const rekeyedMediumSecretMkgUserKey =
await client.retrieveAbeUserDecryptionKey(mediumSecretMkgUserKeyUid)
//
// creating a new medium secret marketing message
//
const mediumSecretMkgData = new TextEncoder().encode(
"medium_secret_mkg_message"
)
encrypter = new CoverCryptHybridEncryption(policy, rekeyedPublicKey)
const newMediumSecretMkgCiphertext = encrypter.encrypt(
"Department::MKG && Security Level::Medium Secret",
mediumSecretMkgData
)
//
// decrypting the messages with the rekeyed key
//
// lowSecretMkgCiphertext
const oldMediumSecretMkgCleartext = new CoverCryptHybridDecryption(
rekeyedMediumSecretMkgUserKey
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgData, oldMediumSecretMkgCleartext)
// newMediumSecretMkgCiphertext
const newMediumSecretMkgCleartext = new CoverCryptHybridDecryption(
rekeyedMediumSecretMkgUserKey
).decrypt(newMediumSecretMkgCiphertext)
assert(mediumSecretMkgData, newMediumSecretMkgCleartext)
//
// decrypting the messages with the NON rekeyed key
//
// lowSecretMkgCiphertext
const plaintext_ = new CoverCryptHybridDecryption(
originalMediumSecretMkgUserKey
).decrypt(lowSecretMkgCiphertext)
assert(lowSecretMkgData, plaintext_)
// newMediumSecretMkgCiphertext
try {
// will throw
new CoverCryptHybridDecryption(originalMediumSecretMkgUserKey).decrypt(
newMediumSecretMkgCiphertext
)
} catch (error) {
// ==> the non rekeyed key cannot decrypt new message after rotation
}
console.log("Succeeded!")
})()