Encryption of data at rest

Encryption of data at rest

Envelope Encryption approach

openg2p-registry will generate a cleartext-DEK (Data Encryption Key) at startup

openg2p-registry will sign this DEK using PKI (Mosip Keymanager) - Asymmetric

This ciphertext-DEK will be persisted in the K8S Secrets

During Startup, registry will call KMS and get the cleartext-DEK and keep this in Memory

Some columns (the implementation model will decide which columns to encrypt) will be encrypted

DB Column encryption will be Symmetric Encryption using AES

So DB encryption/decryption will not have latency associated with KMS services

Should I use NONCE resistance?? Possibly overkill?? There is AES-GCM. You will have to store the NONCE value along with the ciphertext (each column/value will have a different NONCE)


AES without GCM

import os

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

from cryptography.hazmat.primitives import padding

class AESCipher:

BLOCK_SIZE = 128 # AES block size in bits

@staticmethod

def encrypt(plaintext: str, key: bytes) -> bytes:

# Convert plaintext to bytes

plaintext_bytes = plaintext.encode("utf-8")

# PKCS7 pad

padder = padding.PKCS7(AESCipher.BLOCK_SIZE).padder()

padded_data = padder.update(plaintext_bytes) + padder.finalize()

# Generate a random 16-byte IV

iv = os.urandom(16)

cipher = Cipher(

algorithms.AES(key),

modes.CBC(iv)

)

encryptor = cipher.encryptor()

ciphertext = encryptor.update(padded_data) + encryptor.finalize()

# You must store IV + ciphertext together

return iv + ciphertext

@staticmethod

def decrypt(blob: bytes, key: bytes) -> str:

iv = blob[:16]

ciphertext = blob[16:]

cipher = Cipher(

algorithms.AES(key),

modes.CBC(iv)

)

decryptor = cipher.decryptor()

padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()

# Unpad the plaintext

unpadder = padding.PKCS7(AESCipher.BLOCK_SIZE).unpadder()

plaintext_bytes = unpadder.update(padded_plaintext) + unpadder.finalize()

return plaintext_bytes.decode("utf-8")


from sqlalchemy import Column, Integer, LargeBinary

from sqlalchemy.orm import declarative_base

from sqlalchemy.ext.hybrid import hybrid_property

from crypto import AESCipher, PLAINTEXT_DEK

Base = declarative_base()

class G2PRegister(Base):

__abstract__ = True

_register_mnemonic_ = None

def encrypt_value(self, value: str) -> bytes:

if not value:

return None

return AESCipher.encrypt(value, PLAINTEXT_DEK)

def decrypt_value(self, blob: bytes) -> str:

if not blob:

return None

return AESCipher.decrypt(blob, PLAINTEXT_DEK)


from sqlalchemy import Column, Integer, LargeBinary

from sqlalchemy.orm import declarative_base

from sqlalchemy.ext.hybrid import hybrid_property

from crypto import AESCipher, PLAINTEXT_DEK

Base = declarative_base()

class FarmerRegister(G2PRegister):

_register_mnenomic_ = "farmer"

full_name = Column(LargeBinary, nullable=True)

@hybrid_property

def full_name(self) -> str:

return self.decrypt_value(self.full_name)

@full_name.setter

def full_name(self, fullname_plaintext: str):

self.full_name = self.encrypt_value(fullname_plaintext)

Last updated

Was this helpful?