I’ve been following the encryption guide here for generating data encryption keys for the client side encryption process https://docs.mongodb.com/drivers/use-cases/client-side-field-level-encryption-guide
I’m trying to test client side encryption locally to a database that I upgraded from community edition to enterprise but I always get null when I try to do the verification step in Section B Step 4. Does a brand new encryption database have to be created for this to work? I was hoping just to add __keyvault to the existing db i have locally
Just for some more specifics I have the following code to generate the data encryption key
const fs = require('fs-extra')
const { MongoClient } = require('mongodb');
const { ClientEncryption } = require('mongodb-client-encryption')
const path = './master-key.txt';
const localMasterKey = fs.readFileSync(path);
const kmsProviders = {
local: {
key: localMasterKey,
},
};
const base64 = require('uuid-base64');
const username = process.env.PAPER_DB_USER
const pass = process.env.PAPER_DB_PASS
const connectionString = `mongodb://${username}:${pass}@localhost:27017`;
const keyVaultNamespace = 'db.__keyVault';
const client = new MongoClient(connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
async function main() {
try {
await client.connect();
console.log("hello clientEncryption")
const encryption = new ClientEncryption(client, {
keyVaultNamespace,
kmsProviders,
});
console.log("done")
const key = await encryption.createDataKey('local');
console.log("key made")
const base64DataKeyId = key.toString('base64');
console.log("base64 key made")
const uuidDataKeyId = base64.decode(base64DataKeyId);
console.log('DataKeyId [UUID]: ', uuidDataKeyId);
console.log('DataKeyId [base64]: ', base64DataKeyId);
} finally {
await client.close();
}
}
main();
Output:
Then I use the following code to verify:
const { MongoClient } = require('mongodb');
const username = process.env.PAPER_DB_USER
const pass = process.env.PAPER_DB_PASS
const connectionString = `mongodb://${username}:${pass}@localhost:27017`;
const keyVaultDb = 'db';
const keyVaultCollection = '__keyVault';
const base64KeyId = '6exu+2ObR8yYaQo/RJe5Gw=='; // use the base64 data key id returned by gen_data_encrypt_key.js in the prior step
const client = new MongoClient(connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const base64 = require('uuid-base64');
async function main() {
try {
await client.connect();
const keyDB = client.db(keyVaultDb);
const keyColl = keyDB.collection(keyVaultCollection);
console.log("base64KeyId", base64KeyId)
const uuidDataKeyId = base64.decode(base64KeyId);
console.log("uuidDataKeyId ", uuidDataKeyId)
const query = {
_id: base64KeyId,
};
const dataKey = await keyColl.findOne(query);
console.log(dataKey);
} finally {
await client.close();
}
}
main();
Output:
And this is what it looks like on the __keyvault connection in the database
Lastly this is the version of mongoDB that I am currently using
For now I can’t figure out how to make it show with just querying base 64 string, I ended up using another package uuid-mongodb https://www.npmjs.com/package/uuid-mongodb to decode it, then put it back into its proper uuid and then the query would work. Not ideal but it functions
...
const UUID = require('uuid-mongodb');
const uuidDataKeyId = UUID.from(base64.decode(base64KeyId));
console.log("uuidDataKeyId ", uuidDataKeyId)
console.log("typeof uuidDataKeyId", typeof uuidDataKeyId)
const query = {
_id: uuidDataKeyId,
};
const dataKey = await keyColl.findOne(query);
console.log(dataKey);
After I finally dont get a null result
wan
(Wan Bachtiar)
July 7, 2020, 5:02am
7
Hi @Andrew_Dravucz , and welcome to the forum!
There is a missing step in the snippet code posted on the documentation page. It should have converted the base64
string into a binary format first before using it in the query. This is because the data stored in the collection db.__keyVault
is also in binary format.
So instead of the following snippet as mentioned on the page:
const query = {
_id: base64KeyId,
};
const dataKey = await keyColl.findOne(query);
It should have been:
let base64KeyIdBinary = new Binary(
Buffer.from(base64KeyId, 'base64'),
Binary.SUBTYPE_UUID);
const query = {
_id: base64KeyIdBinary,
};
const dataKey = await keyColl.findOne(query);
A patch to fix the documentation is currently pending review.
Regards,
Wan.
1 Like
Great thanks @wan that makes sense, I was able to piece that together with some trial and error. Is that Binary builder from the mongodb library directly like mongo client?
wan
(Wan Bachtiar)
July 13, 2020, 5:58am
9
Hi @Andrew_Dravucz ,
Yes, correct. The example import statement would be:
let Binary = require('mongodb').Binary;
Regards,
Wan.