How to Build a Fully Homomorphic Encrypted Database with Python and PyCryptodome
Fully Homomorphic Encryption (FHE) is a transformative approach to cryptography that allows data to remain encrypted during processing, providing both security and functionality. This guide will walk you through building a system where data is stored, queried, and updated in encrypted form using Python and the PyCryptodome library.
Understanding Fully Homomorphic Encryption
Fully Homomorphic Encryption (FHE) allows computations such as addition and multiplication to be performed directly on encrypted data. The results of these computations are still encrypted and can be decrypted to reveal the correct output. FHE is especially useful for secure cloud computing, private data analysis, and encrypted machine learning.
Why Build an Encrypted Database?
An encrypted database allows you to store sensitive data securely while maintaining the ability to query and process it without decrypting it. This is ideal for use cases like:
- Cloud storage: Encrypt data before sending it to the cloud but still perform computations.
- Private machine learning: Train models on encrypted data without exposing raw information.
- Secure medical or financial records: Protect sensitive data while performing operations on it.
Step-by-Step Guide to Building the Encrypted Database
Step 1: Install PyCryptodome
Start by installing the PyCryptodome library, which we will use for encryption and decryption.
pip install pycryptodome
Step 2: Implement Basic Encryption and Decryption
Before building the database, let’s implement basic encryption and decryption functions using AES (Advanced Encryption Standard) with the PyCryptodome library.
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
# Key generation
key = get_random_bytes(16) # AES-128
# Encryption function
def encrypt(data, key):
cipher = AES.new(key, AES.MODE_CBC)
ciphertext = cipher.encrypt(pad(data.encode(), AES.block_size))
return cipher.iv, ciphertext
# Decryption function
def decrypt(iv, ciphertext, key):
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
return plaintext.decode()
In this step, we’ve defined two functions: encrypt()
for encrypting data and decrypt()
for decrypting it. The encrypt()
function uses padding to ensure the data fits into blocks required by AES, and the decrypt()
function reverses this process.
Step 3: Create an Encrypted Database
Now, we’ll create an encrypted database. This database will store data in encrypted form, and we’ll be able to query it and update its records securely.
class EncryptedDatabase:
def __init__(self, key):
self.key = key
self.db = {}
def insert(self, record_id, data):
iv, encrypted_data = encrypt(data, self.key)
self.db[record_id] = (iv, encrypted_data)
print(f"Record {record_id} inserted.")
def query(self, record_id):
if record_id in self.db:
iv, encrypted_data = self.db[record_id]
decrypted_data = decrypt(iv, encrypted_data, self.key)
print(f"Record {record_id}: {decrypted_data}")
else:
print(f"Record {record_id} not found.")
In this step, we’ve created an EncryptedDatabase
class with two main methods:
insert()
: Encrypts and stores data.query()
: Decrypts and retrieves the data.
Each record is stored as a tuple of the initialization vector (IV) and the encrypted data, making it secure.
Step 4: Insert and Query Data
Next, let’s insert some records into the encrypted database and query them to see how it works.
# Create a new encrypted database
key = get_random_bytes(16) # Generate a random key
db = EncryptedDatabase(key)
# Insert records
db.insert(1, "Alice's salary: 1000")
db.insert(2, "Bob's salary: 1200")
# Query records
db.query(1)
db.query(2)
The above example inserts records for Alice and Bob into the encrypted database. You can query the database to retrieve and decrypt these records.
Step 5: Simulating Homomorphic Operations on Encrypted Data
To simulate homomorphic operations, we can decrypt, perform operations like addition, and then re-encrypt the data. True FHE would allow operations directly on encrypted data without decrypting, but for simplicity, we’ll demonstrate a simplified version.
def homomorphic_add(ciphertext1, ciphertext2, key):
# Decrypt both ciphertexts
plaintext1 = decrypt(ciphertext1[0], ciphertext1[1], key)
plaintext2 = decrypt(ciphertext2[0], ciphertext2[1], key)
# Perform addition on the plaintexts
result = str(int(plaintext1.split(": ")[1]) + int(plaintext2.split(": ")[1]))
# Encrypt the result
return encrypt(result, key)
# Encrypt two salary records
iv1, enc_num1 = encrypt("1000", key)
iv2, enc_num2 = encrypt("1200", key)
# Perform homomorphic addition
iv_result, enc_result = homomorphic_add((iv1, enc_num1), (iv2, enc_num2), key)
# Decrypt the result
decrypted_result = decrypt(iv_result, enc_result, key)
print(f"Homomorphic Addition Result: {decrypted_result}")
Here, two salary records are encrypted, decrypted, added, and then re-encrypted to simulate a homomorphic operation.
Step 6: Updating Encrypted Records
You can also update encrypted records securely, performing computations on the decrypted values and then re-encrypting the updated values.
def query_and_update(record_id, increment):
iv, encrypted_data = db.db[record_id]
current_data = decrypt(iv, encrypted_data, db.key)
new_value = str(int(current_data.split(": ")[1]) + increment)
updated_data = current_data.split(": ")[0] + ": " + new_value
db.insert(record_id, updated_data)
print(f"Updated Record {record_id}: {updated_data}")
# Update Alice's salary
query_and_update(1, 200)
db.query(1)
In this step, we query a record, update its value, and then re-encrypt and store the updated record securely.
Conclusion
Building a fully homomorphic encrypted database using Python and PyCryptodome helps you secure sensitive data while still allowing operations on that data. While this tutorial provides a basic approach, true fully homomorphic encryption is more complex and computationally intensive.
With the code and steps provided here, you can expand this project to explore more complex operations and begin implementing privacy-preserving techniques in your systems. Continue to refine and build on this knowledge, and you will unlock the potential of FHE in various security-critical applications.