Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

673
Views
Decrypt data in a PostgreSQL query which was encrypted with C#

There is some code we have in C# which encrypts and decrypts data for storing in a postgresql database. The code for decrypting is as follows:

public string Decrypt(string val)
{
    var sb = new StringBuilder();
    string[] split = val.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

    foreach (string s in split)
    {
        sb.Append(Encoding.UTF8.GetString(Decode(Convert.FromBase64String(s))));
        sb.Append(" ");
    }
    sb.Remove(sb.Length - 1, 1); // Remove last space

    return sb.ToString();
}

private static byte[] Decode(byte[] encodedData)
{
    var symmetricAlgorithm = Aes.Create();
    symmetricAlgorithm.Key = HexToByteArray("<aes key>");

    var hashAlgorithm = new HMACSHA256();
    hashAlgorithm.Key = HexToByteArray("<hash key>");

    var iv = new byte[symmetricAlgorithm.BlockSize / 8];
    var signature = new byte[hashAlgorithm.HashSize / 8];
    var data = new byte[encodedData.Length - iv.Length - signature.Length];

    Array.Copy(encodedData, 0, iv, 0, iv.Length);
    Array.Copy(encodedData, iv.Length, data, 0, data.Length);
    Array.Copy(encodedData, iv.Length + data.Length, signature, 0, signature.Length);

    // validate the signature
    byte[] mac = hashAlgorithm.ComputeHash(iv.Concat(data).ToArray());

    if (!mac.SequenceEqual(signature))
    {
        // message has been tampered
        throw new ArgumentException();
    }

    symmetricAlgorithm.IV = iv;

    using (var memoryStream = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(memoryStream, symmetricAlgorithm.CreateDecryptor(), CryptoStreamMode.Write))
        {
            cryptoStream.Write(data, 0, data.Length);
            cryptoStream.FlushFinalBlock();
        }
        return memoryStream.ToArray();
    }
}

private static byte[] HexToByteArray(string hex)
{
    return Enumerable.Range(0, hex.Length).
        Where(x => 0 == x % 2).
        Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).
        ToArray();
}

The requirement I have now is that we want to be able to decrypt within an SQL query.. I have discovered the PGP_SYM_DECRYPT function, as well as some others like Encode()/Decode() for base64 strings and a decrypt_iv() function as well. Only I am uncertain how to use these to decrypt data.

Any crypto experts that could help me out here?

Alternatively, is there some equivalent of MSSQL's CLR functions for Postgres?

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

So what I'm inferring from the decryption code is the following:

Your encodedData is split up into three parts

  • Initialization vector (IV)
  • Ciphertext
  • Signature

You are using AES to encrypt/decrypt the data and use HMACSHA256 for the signature.

  • The AES block size in C# is fixed to 128 bits.
  • The signature is 256 bits in length (thus SHA256) (ref)
  • The IV is blockSize / 8 bytes long -> 16 bytes
  • Signature is 32 bytes

That means your encoded data is split up as follows:

[IV 16 bytes][Ciphertext n bytes][Signature 32 bytes]

To decrypt this with postgres, you need to have the pgcrypto module enabled. Lets say we have a table Foo with the field data of type bytea which contains the encrypted data. By using the Raw Encryption Functions of pgcrypto you should be able to decrypt this utilizing binary string operators to extract the parts.

  • (octet_length(data) - 16 - 32) should be the ciphertext length
  • substring(data from 0 for 16) should get the IV
  • substring(data from 16 for (octet_length(data) - 16 - 32)) should get the ciphertext
  • substring(data from (octet_length(data) - 32) for 32 should get the signature.

This results in:

SELECT decrypt_iv(
    substring(data from 16 for (octet_length(data) - 16 - 32)),
    "Decryption Key as bytes"::bytea,
    substring(data from 0 for 16),
    'aes'
)
FROM Foo

The signature is disregarded in this example, but you should be able to verify it in a similar way with General Hashing Functions. If the decryption key is wrong, you will probably just get garbage data.

over 4 years ago · Santiago Trujillo Report

0

Thanks to @JensV for his answer.. we finally came up with the following:

CREATE OR REPLACE FUNCTION aes_cbc_mix_sha256_decrypt(data text, key text) RETURNS text
language plpgsql
AS
$$
DECLARE
  res text;
  dataHex text;
  iv bytea;
  aes_key bytea;
  encrypted_data bytea;
BEGIN
  SELECT decode(key, 'hex') INTO aes_key;
  SELECT encode(decode(data, 'base64'), 'hex') INTO dataHex;
  SELECT decode(SUBSTRING(dataHex FROM 1 FOR 32), 'hex') INTO iv;
  SELECT decode(SUBSTRING(dataHex FROM 33 FOR (SELECT LENGTH(dataHex) - 32 - 64)), 'hex') INTO encrypted_data;
  SELECT encode(decrypt_iv(encrypted_data, aes_key, iv, 'aes-cbc'), 'escape') INTO res;
  RETURN res;
  
    EXCEPTION WHEN others THEN
        RETURN data;
END;
$$
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!