Skip to content

Instantly share code, notes, and snippets.

@sarjarapu
Created January 23, 2020 15:23
Show Gist options
  • Save sarjarapu/37b11089c7d2f7b3e3c01b932b2e658c to your computer and use it in GitHub Desktop.
Save sarjarapu/37b11089c7d2f7b3e3c01b932b2e658c to your computer and use it in GitHub Desktop.
A JavaScript to show MongoDB client-side field-level encryption can help you implement solutions for California Consumer Privacy Act. The deletion of the data encryption key will render all the consumers' data permanently unreadable be it in current database or in historical snapshots.
// rules for automation encryption
var schemaMap = {
"health_care_app.patients": {
"bsonType": "object",
"properties": {
"medRecNum": {
"bsonType": "int"
},
"firstName": {
"bsonType": "string"
},
"lastName": {
"bsonType": "string"
},
"ssn": {
"encrypt": {
"bsonType": "string",
"algorithm": SSN_ENCRYPTION_ALGORITHM,
"keyId": [SSN_ENCRYPTION_KEY_UUID]
}
},
"mobile": {
"encrypt": {
"bsonType": "string",
"algorithm": MOBILE_ENCRYPTION_ALGORITHM,
"keyId": [MOBILE_ENCRYPTION_KEY_UUID]
}
},
"comment": {
"bsonType": "string"
}
}
}
};
// lets recreate the client-side Field-Level encryption options with schema
var csfleOptionsWithSchema = {
"keyVaultNamespace" : "encryption.__dataKeys",
"kmsProviders" : {
"local" : {
"key" : BinData(0, LOCAL_KEY)
}
},
"schemaMap" : schemaMap
};
// functions to create a patient document with unique data encryption key for each
function getOrCreateKey(client, keyName) {
if (client.getKeyVault().getKeyByAltName(keyName).toArray().length === 0) {
client.getKeyVault().createKey("local", "", [keyName]);
}
return client.getKeyVault().getKeyByAltName(keyName).toArray()[0]._id;
}
function getUserKeys(client, userId) {
return {
ssn: getOrCreateKey(client, `an-${userId}-ssn`),
mobile: getOrCreateKey(client, `an-${userId}-Mobile`)
}
}
function createUserWithSpecialKey(client, userid) {
var u = userid;
var userKeys = getUserKeys(client, u);
client.getDB("health_care_app").getCollection("patients").insert({
"_id": u,
"medRecNum": u,
"firstName": `fname${u}`,
"lastName": `lname${u}`,
"city": 'city-' + u % 3,
"ssn": client.encrypt(userKeys.ssn, `${u}${u}${u}-${u}${u}-${u}${u}${u}${u}`, SSN_ENCRYPTION_ALGORITHM),
"mobile": client.encrypt(userKeys.mobile, `${u}${u}${u}-${u}${u}${u}-${u}${u}${u}${u}`, MOBILE_ENCRYPTION_ALGORITHM),
"comment": `User ${u} SSN/Phone are encrypted with user specific key.`
});
}
var csfleClient = Mongo("mongodb://localhost:28000", csfleOptionsWithSchema);
var csfleDB = csfleClient.getDB("health_care_app");
// drop the existing collection
csfleDB.getCollection("patients").drop();
for(var i = 0; i < 10; i++) {
createUserWithSpecialKey(csfleClient, i);
}
// NOTE: Well I was hoping to see the documents to be encrypted for everyone unless I gave that key
csfleDB.getCollection("patients").findOne({_id: 9});
// { "_id" : 9, "medRecNum" : 9, "firstName" : "fname9", "lastName" : "lname9", "ssn" : "999-99-9999", "mobile" : "999-999-9999", "comment" : "User 9 SSN/Phone are encrypted with user specific key." }
// fetch user 9 keys and delete them.
var userKeys = getUserKeys(csfleClient, 9);
csfleClient.getKeyVault().deleteKey(userKeys.ssn);
csfleClient.getKeyVault().deleteKey(userKeys.mobile);
// Record still exists but you cannot decrypt the encrypted values.
csfleDB.getCollection("patients").findOne({_id: 9}, {_id: 1, "medRecNum": 1, "firstName": 1, "lastName": 1, "city": 1, "comment": 1});
// {
// "_id" : 9,
// "medRecNum" : 9,
// "firstName" : "fname9",
// "lastName" : "lname9",
// "city" : "city-0",
// "comment" : "User 9 SSN/Phone are encrypted with user specific key."
// }
// try to fetch all data including the encrypted fields
csfleDB.getCollection("patients").find({_id: 9});
// Error: Invalid keyID
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment