In today’s digital landscape, data security is paramount. As organizations increasingly rely on databases to store sensitive information, the need for robust encryption and hashing mechanisms has never been greater. PostgreSQL, a powerful open-source RDBMS, offers an extension called pgcrypto that provides a suite of cryptographic functions. In this blog post, we will explore what pgcrypto is, its key features, and how to use it effectively to enhance your database security.
The pgcrypto extension was introduced in PostgreSQL 8.1, which was released in 2005. It enables developers to secure sensitive data within the database directly, ensuring that it is protected both at rest and in transit.
What is pgcrypto?
pgcrypto is a popular PostgreSQL extension that provides cryptographic functions for data encryption, decryption, hashing, digital signatures, and random number generation. It allows developers to implement security measures directly within the database, ensuring that sensitive data is protected effectively.
Use Cases:
When using pgcrypto in PostgreSQL, encryption and decryption operations are typically performed at the column level, not the entire table level. This means you can encrypt or decrypt individual column values without affecting the entire table or all columns.
Key Features of pgcrypto:
- Encryption/Decryption: Supports both symmetric (same key for encryption and decryption) and asymmetric (public/private keys) encryption.
- Hashing: Provides functions for generating hash values (e.g., MD5, SHA256).
- Random Data Generation: Can generate random numbers or random data.
- Digital Signatures: Enables the creation and verification of digital signatures.
How to Install and Use pgcrypto
Step 1: Install the pgcrypto Extension
Before using pgcrypto, you need to ensure it’s installed and enabled on your PostgreSQL instance. You can install pgcrypto using the following SQL command:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
Key Functions in pgcrypto:
- Symmetric Encryption and Decryption Functions:
- pgp_sym_encrypt(data, key): Encrypts the data using a symmetric key.
- pgp_sym_decrypt(data, key): Decrypts the data encrypted with a symmetric key.
- Asymmetric Encryption and Decryption Functions:
- pgp_pub_encrypt(data, public_key): Encrypts data using a public key.
- pgp_pub_decrypt(data, private_key): Decrypts data using a private key.
- Hashing Functions:
- digest(data, type): Computes a hash of the input data using the specified algorithm (e.g., SHA-256, MD5).
- hmac(data, key, type): Computes a keyed hash message authentication code (HMAC).
- Password Hashing Functions:
- crypt(password, salt): Hashes a password using a salt, suitable for secure password storage.
- gen_salt(type): Generates a random salt for use with the crypt function.
Step 2: Using Encryption/Decryption Functions
Let’s see how to use the encryption and decryption functions.
2.1 Symmetric Encryption
You can encrypt sensitive data, such as a credit card number, using symmetric encryption with a secret key.
Example of Inserting Encrypted Data:
CREATE TABLE Customer (
customer_id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
phone_number VARCHAR(15),
address VARCHAR(255),
credit_card_number bytea,
password VARCHAR(255)
);
INSERT INTO Customer (name, email, phone_number, address, credit_card_number, password)
VALUES (
'Dhoni',
'dhoni.ms@example.com',
'123-456-7890',
'Ranchi, Bihar',
pgp_sym_encrypt('1234-5678-9876-5432', 'secret_key'), -- Encrypt using the secret key
'msdhoni07'
);
This is how the data would look after encrypting the the column:
SELECT * FROM customer;
)
customer_id │ name │ email │ phone_number │ address │ credit_card_number │ password
────────────┼──────
─┼───
───────────────────┼──────────────┼──────
─────
────┼─────────────────────
─────────────────┼───────────
1 │ Dhoni │ dhoni.ms@example.com │ 123-456-7890 │ Ranchi, Bihar │ xc30d04070302bd0bb96fa909e16a68d24...│ msdhoni07
(1 row
Example of Decrypting Data:
To decrypt the encrypted credit_card_number, use the following query:
SELECT
customer_id,
name,
email,
phone_number,
address,
pgp_sym_decrypt(credit_card_number, 'secret_key') AS decrypted_credit_card_number,
password
FROM Customer;
SELECT
customer_id,
name,
email,
phone_number,
address,
pgp_sym_decrypt(credit_card_number, 'secret_key') AS decrypted_credit_card_number,
password
FROM Customer;
customer_id │ name │ email │ phone_number │ address │ decrypted_credit_card_number │ password
────────────┼───────┼──────────────────────┼──────────────┼───────────────┼──────────────────────────────┼───────────
1 │ Dhoni │ dhoni.ms@example.com │ 123-456-7890 │ Ranchi, Bihar │ 1234-5678-9876-5432 │ msdhoni07
(1 row)
Time: 32.344 ms
2.2 Asymmetric Encryption
Asymmetric encryption uses a pair of keys: a public key for encryption and a private key for decryption.
Generating a Key Pair
To use asymmetric encryption, you first need to generate a PGP key pair. The steps to generate a PGP key pair and use it with pgcrypto are outlined below.
How to Generate a PGP Key Pair for pgcrypto
Step 1: Generate the PGP Key Pair
To generate a PGP key pair, use relevant GPG (GNU Privacy Guard) commands (this step assumes you have GPG already installed on your system). You can use the following command and inputs(make sure you replace the ‘Name-Real’ and ‘Name-Email’ with appropriate values) to generate an RSA key pair:
gpg --batch --generate-key <<EOF
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: Your Name
Name-Email: your.email@example.com
Expire-Date: 0
%no-protection
EOF
This will generate an RSA key pair with the following parameters:
- Key-Type: RSA
- Key-Length: 2048 bits
- Subkey-Type: RSA
- Subkey-Length: 2048 bits
- Name-Real: Your full name
- Name-Email: Your email address associated with the key
- Expire-Date: Set to 0 (no expiration)
- %no-protection: This means that the key will be created without a passphrase (no protection). Normally, a passphrase is used to protect your private key. This option disables that, making the key easier to use but less secure. It’s not recommended for keys used in high-security environments.
Step 2: Verify the Key Pair
After generating the key pair, verify it by running the following command:
gpg --list-keys
gpg --list-secret-keys
This will display the details of your PGP key pair.
Step 3: Export the Public and Private Keys
You need to export both the public and private keys to use them in PostgreSQL.
Export the Public Key:
To export the public key, use the following command replacing your.email@example.com with the value entered for Name-Email in Step#1 above:
gpg --export -a your.email@example.com > pgp_public.key
Export the Private Key:
To export the private key, use the following command replacing your.email@example.com with the value entered for Name-Email in Step#1 above:
gpg --export-secret-key -a your.email@example.com > pgp_private.key
While exporting the private key, the system would prompt you to create a Passphrase. Make sure you enter a value and store it in a safe location (with controlled/restricted access) as you would need it for decrypting the data.
Please enter the passphrase to export the OpenPGP secret key:
____________________
"Your Name <your.email@example.com>"
2048-bit RSA key, ID D72085FEF21BF188,
created 2025-03-03.
Passphrase:
Step 4: Import the Keys into PostgreSQL
Now that you have the keys, store them in PostgreSQL to use them with pgcrypto.
Create a Table to Store the Keys:
CREATE TABLE pgp_keys (
id SERIAL PRIMARY KEY,
key_name VARCHAR(50) UNIQUE NOT NULL,
pubkey TEXT NOT NULL,
privkey TEXT NOT NULL
);
Insert the Keys into the Table:
Use the following statement to insert the keys into the table. You could assign any desired name instead of ‘your_key_name'
. The values for the next two columns should come from the pgp_public.key
and pgp_private.key
files created above:
INSERT INTO pgp_keys (key_name, pubkey, privkey)
VALUES (
'your_key_name',
'-----BEGIN PGP PUBLIC KEY BLOCK----- … -----END PGP PUBLIC KEY BLOCK-----',
'-----BEGIN PGP PRIVATE KEY BLOCK----- … -----END PGP PRIVATE KEY BLOCK-----'
);
Step 5: Use the Keys for Encryption and Decryption in PostgreSQL
Now that the keys are in the database, you can use pgcrypto functions like pgp_pub_encrypt
and pgp_pub_decrypt
to encrypt and decrypt data. After encrypt the column
Example of Encrypting Data with the Public Key:
CREATE TABLE Customer (
customer_id SERIAL PRIMARY KEY,
name VARCHAR(100),
phone_number VARCHAR(15),
address VARCHAR(255),
email TEXT,
password BYTEA -- Store password or any other sensitive data
);
INSERT INTO Customer (name, phone_number, address, email, password)
VALUES (
'Virat',
'987-654-3210',
'Delhi, India',
'virat.kohli@example.com',
pgp_pub_encrypt('Vratkohli18', dearmor((SELECT pubkey FROM pgp_keys WHERE key_name = 'your_key_name')))
);
After encrypt the column:
SELECT * FROM customer;customer_id │ name │ phone_number │ address │ encrypted_email │ password >
>
────────────┼─────
──┼──────────────┼────────────
──┼─────────────────
────────┼─────────────
───────────────
────────────────────────
1 │ Virat │ 987-654-3210 │ Delhi, India │ virat.kohli@example.com │ \xc1c04c03a3df036234e28011010800b7cdfa41ad3f13d8...>
(1 row)
Time: 0.733 ms
Example of Decrypting Data with the Private Key:
SELECT customer_id,
phone_number,
address,
email,
pgp_pub_decrypt(password, dearmor((SELECT privkey FROM pgp_keys WHERE key_name = 'your_key_name')), 'YourPassphrase') AS password
FROM customer;
SELECT
customer_id,
name,
phone_number,
address,
encrypted_email,
pgp_pub_decrypt(password, dearmor((SELECT privkey FROM pgp_keys WHERE key_name = 'lokesh_key')), 'Postgres123@') AS password
FROM
customer;
customer_id │ name │ phone_number │ address │ encrypted_email │ password
────────────┼──────┼──────────────┼──────────────┼─────────────────────────┼─────────────
1 │Virat │ 987-654-3210 │ Delhi, India │ virat.kohli@example.com │ Vratkohli18
(1 row)
In the query, YourPassphrase is the passphrase used to decrypt the private key (privkey) stored in the pgp_keys table. This passphrase is required to access the private key for decryption purposes.
Conclusion
By following these steps, you can leverage pgcrypto to encrypt, decrypt, and securely store sensitive data within PostgreSQL. Generating a PGP key pair and importing the keys into your database is an essential step for using asymmetric encryption with pgcrypto. This approach ensures that your sensitive data remains secure both at rest and during transmission.
In the next blog, we will dive deeper into additional pgcrypto functions, including hashing and digital signatures, to further enhance the security of your PostgreSQL databases.