Testing Client Side encryption locally, returning null value

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: image

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: image

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
image

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
image

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?

Hi @Andrew_Dravucz,

Yes, correct. The example import statement would be:

let Binary = require('mongodb').Binary;

Regards,
Wan.