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?

