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?
So what I'm inferring from the decryption code is the following:
Your encodedData is split up into three parts
You are using AES to encrypt/decrypt the data and use HMACSHA256 for the signature.
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 lengthsubstring(data from 0 for 16) should get the IVsubstring(data from 16 for (octet_length(data) - 16 - 32)) should get the ciphertextsubstring(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.
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;
$$