In [1]:
import bson
from bson.json_util import loads, dumps
from bson.binary import Binary
import pysodium
from bsonsearch import bsoncompare
bc = bsoncompare()
You want to allow access to some data, but perhaps not all data in a particular document.
You must start by generating a public/private key pair on the secure side, and exposing only the public key to untrusted users.
In [2]:
PUBLIC_KEY = Binary('\x8eB\x11\xd5ht\x93\x05\xee\xed\x10\xad\xb4\x90\xb7]\x92\x04\xac\x82\xb5\xa2"v\xf9[\xd6^\x14\x8b\x12\x1d', 0)
In [3]:
sensitive_subdocument = {"sensitive":"triple pinky swear"}
document = {
"_id":1,
"name":"bsonsearch",
"super_secret_data":sensitive_subdocument
}
print document
In [4]:
plaintext_spec = {"super_secret_data.sensitive":"triple pinky swear"}
plaintext_matc = bc.generate_matcher(plaintext_spec)
print "Matches", bc.match(plaintext_matc, document)
but maybe you don't want that tripple pinky swear value available to just anyone to search on
so we're going to append the sensitve subdocument as an encrypted blob using assymentric encryption
In [5]:
secure_sensitive_subdocument = Binary(pysodium.crypto_box_seal(bson.BSON.encode(sensitive_subdocument),
PUBLIC_KEY))
secure_document = {
"_id":1,
"name":"bsonsearch",
"super_secret_data": secure_sensitive_subdocument
}
print secure_document
this document will no longer match the original
In [6]:
print "Matches", bc.match(plaintext_matc, secure_document)
now we need the secret key,
The person generating the document didn't need the secret key,
but the person reading/querying the document does.
The query uses the $sealOpen command and provides the keys and a query to the inside document
notice the change in query, where the namespace is broken between the entry key and the $query
the namespace "secure_secret_data" is accounted for in the $sealOpen command, and the query acts on the value of that namespace.
In [7]:
SECRET_KEY = Binary('\xe2\x16\x9a,\xb1\x9b\xb4\xf67\xe9\xf8\x83\x0f"_\xa8}t\xd2i:\xbb\xfd\xb5\x8a\x89X.\x1b\x13\x92Z', 0)
spec_decrypt = {"super_secret_data":{"$sealOpen":{"$keys":{"pk":PUBLIC_KEY,
"sk":SECRET_KEY},
"$query":{"sensitive":"triple pinky swear"}
}
}
}
In [8]:
matcher_decrypt = bc.generate_matcher(spec_decrypt)
print "Decrypt with key matches ---->", bc.match(matcher_decrypt, secure_document)
print "Non-decrypt should be false ->", bc.match(plaintext_matc, secure_document)
In [9]:
SECURE_KEYPAIR = pysodium.crypto_box_keypair()
SECURE_KEYPAIR_DICT = {"pk":Binary(SECURE_KEYPAIR[0]),
"sk":Binary(SECURE_KEYPAIR[1])}
SECURE_KEYPAIR_DICT
Out[9]:
In [9]: