Enhancing Data Privacy Protection in Indonesia: Integrating Next.js with PgCrypto for Secure Solutions

M Sadewa Wicaksana
5 min readOct 12, 2024

--

This story start when in my current jobs there are regulations to add some security in data privacy because of the government regulations. The government regulations is about personal data protection law in Indonesia which passed in 2022. Personal data is any data about an individual that can identify them directly or indirectly, which includes names, identification numbers, location data, and online identifiers.

To comply with these regulations, I conducted thorough research and identified what I believe to be the most effective approach for safeguarding user data and preventing network breaches. My approaches like in the image below.

I’ll explain it in three parts,

  1. PostgreSQL
  2. Next.js
  3. Scenario

1. PostgreSQL

Implement encryption in PostgreSQL is a huge challenge. There are several information we need to consider, such as performance, extensions, and data type. Therefore, PostgreSQL itself had a built in function which the name is pgcrypto. References: https://www.postgresql.org/docs/current/pgcrypto.html

This extension is supported for PostreSQL versions higher than 12. There are some key functions available with pgcrypto such as

a. Encryption and Decryption

b. Hashing functions

c. Random Data Generation

d. Key Management

e. Data Integrity

In this story, we only focus on point a. How to encrypt and decrypt our personal data information in database.

Explanation

install extensions

CREATE EXTENSION IF NOT EXISTS pgcrypto;

Run sample code to ensure that your pgcrypto is work properly

SELECT encode(pgp_sym_encrypt('hello world', 'keynya'), 'hex') AS encrypted_data;

Based on image above pgp_sym_encrypt is used to encrypt the information plaint text into cipher, which the first arguments is the plain text and the second arguments is the key of our cipher to decrypt or encrypt information.

Implementation

My sample data users in database is such as image below which the data is plain text, and don’t forget to change the data type into text to make sure there no missing information if we use varchar because the text is too long.

To convert it into cipher we will do command update to encrypt that name informations using this command

UPDATE users SET "name" = encode(pgp_sym_encrypt("name", 'keynya'), 'hex')

Check it again using command SELECT SQL

Done, our columns name is changed into cipher information. 😁😁

2. Next.js

In this story implement with my next versions is 14, page router concept, and implement server actions with axios. Task of the Next.js is only for decrypt the information from PostgreSQL but in the client side. Therefore, to handle that we need to install library which support to decrypt the postgresql information using openpgp.js.

Explanation

To install that library run this command

npm install --save openpgp

OpenPGP is an encryption standard used to secure emails, files, and other data. With OpenPGP you can allow for Encryption, Digital Signatures, and Key Management.

Scenario

a. Encryption

Based on the image above, the encryption process is do by client side using openpgp then send it to backend using server actions. Sample code client side encryption.

const onSubmit = forms.handleSubmit(async (values) => {
const formData = new FormData();
forms.setValue("exclude.dataUser.phone", "");
forms.setValue("exclude.dataUser.alasan_pembuatan_akun", "");

forms.setValue("exclude.dataUser.name", await encryptAesDBKey(values.exclude.dataUser.name));
forms.setValue("exclude.dataUser.birth_date", await encryptAesDBKey(values.exclude.dataUser.birth_date));
forms.setValue("exclude.dataUser.ktp", await encryptAesDBKey(values.exclude.dataUser.ktp));
forms.setValue("exclude.dataUser.gender", await encryptAesDBKey(values.exclude.dataUser.gender));
})
const encryptAesDBKey = async (data: string) => {
try {
const message = await createMessage({ text: data });

// Encrypt the message
const encrypted = await encrypt({
message,
passwords: ["d9bdc6209164d622"],
format: "binary",
});

// Convert the encrypted message to hex
const encryptedHex = Buffer.from(new Uint8Array(encrypted)).toString("hex");
return encryptedHex;
} catch (error) {
return data;
}
};

validation ciphertext with PgCrypto

SELECT pgp_sym_decrypt(decode('c32e040903087b6a93f785abd8d7e0d9c428f3c909ce7503448ab00a4ee4906380e532e7ffb79a32f28415b08c7fa6dcd23801529a85e57748900191d5b7e8128b1af624ab04d3f95003ba059d3dfa57b8632ae253b6b7ab8ba87f3be8c40d8bc1c55b8365d8d88d8145', 'hex'), 'd9bdc6209164d622')

b. Decryption

To prevent data breaches from network browsers, we need to decrypt the ciphertext to plain text in client side. Sample code to decrypt the information is like below

const processAfterProfile = async (profileData: ProfileData, isIAM: boolean = false) => {
/**Information needed in user and decode it */
const { id, name, email, phone, file_avatar } = profileData.user;

const newUser = {
id,
name: await decryptAesDBKey(name),
email,
phone: await decryptAesDBKey(phone),
file_avatar,
};
};
const decryptAesDBKey = async (key: string) => {
try {
// Decode the hex-encoded data
const encryptedData = Buffer.from(key, "hex");

// Read the encrypted message
const message = await readMessage({
binaryMessage: encryptedData,
});

// Decrypt the message
const { data: decryptedData } = await decrypt({
message,
passwords: ["d9bdc6209164d622"],
format: "utf8",
});

return decryptedData;
} catch (error) {
return key;
}
};

--

--

M Sadewa Wicaksana
M Sadewa Wicaksana

Written by M Sadewa Wicaksana

Artificial Intelligence and Fullstack Engineering Enthusiast and Still Learning

No responses yet