michelp / pgsodium

Modern cryptography for PostgreSQL using libsodium.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Updated value in secret column does not get encrypted

timreibe opened this issue · comments

Hi everyone,

following my setup in #73, I have a secret value stored in secret_column, which is encrypted at insert.
Now, when updating the value, I expect it to be encrypted again, but it won't. Edit: It is stored as clear text.

Is this behavior expected, or is this, again, an issue I have with supabase?

Kind regards
Tim

edit: I added the database setup scripts in my comment below

As a workaround, I created an update trigger, which sets a new key_id and nonce and encryptes the secret value again with both.

  • Setup Database
    In this case, I have a column named owner which references to my (supabase) users table.
CREATE TABLE table_name1 (
   id uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
   owner uuid NOT NULL REFERENCES auth.users (id),
   key_id uuid NOT NULL REFERENCES pgsodium.key(id) DEFAULT (pgsodium.create_key()).id,
   nonce bytea NOT NULL DEFAULT pgsodium.crypto_aead_det_noncegen(),
   secret_column text NOT NULL DEFAULT 'undefined'::text
);

SECURITY LABEL FOR pgsodium
  ON COLUMN table_name1.secret_column
  IS 'ENCRYPT WITH KEY COLUMN key_id NONCE nonce ASSOCIATED owner';

CREATE VIEW decrypted_table_name1 AS
  SELECT id,
         convert_from(pgsodium.crypto_aead_det_decrypt(
           pg_catalog.decode(secret_column, 'base64'),
           pg_catalog.convert_to(owner::text, 'utf8'),
           key_id::uuid,
           nonce
         ), 'utf8') AS secret_column
         FROM table_name1;
  • Create Trigger
create or replace function set_table_name1_pgsodium_values()
    returns trigger
as
$$
begin

    new.key_id := (pgsodium.create_key()).id;
    new.nonce :=  pgsodium.crypto_aead_det_noncegen();

    new.secret_column := pg_catalog.encode(
        pgsodium.crypto_aead_det_encrypt(
            pg_catalog.convert_to(new.secret_column, 'utf8'),
            pg_catalog.convert_to(old.owner::text, 'utf8'),
            new.key_id,
            new.nonce
        ),
    'base64');
    return new;
end ;
$$
    language plpgsql;

create trigger trg_set_table_name1_pgsodium_values
    before update
    on table_name1
    for each row
execute procedure set_table_name1_pgsodium_values();

Now, when updating the value, I expect it to be encrypted again, but it won't.

What do you mean "it won't"? Does the updated data is written in clear text/bytea?

Here is a similar Q+A if it could help: #61 (comment)

Hi @ioguix, the updated data is written in clear text and not encrypted.

Thanks for the Q&A, so to trigger the encryption correctly, I have to update the value via the decrypted view, correct? Is there any advantage/disadvantage over having a trigger that encrypts the value on an update call?

Another thing is: I'd like to update the key_id and nonce on every change of the secret column, can I somehow integrate this in an alternative way than using an update trigger?

Hi,

I have to update the value via the decrypted view, correct?

Not necessarily if you don't build the new value with the old one.

I have no idea why your trigger does not fire:

76=# select secret_column, decrypted_secret_column from decrypted_table_name1 ;
                  secret_column                   | decrypted_secret_column 
--------------------------------------------------+-------------------------
 ke6mSPa146SZZFdMa+8bJzN8bHjg/sC45oGEUk3UzNRsX21/ | chut
(1 row)

76=# update table_name1 set secret_column = 'chuuuuuut';
UPDATE 1
76=# select secret_column, decrypted_secret_column from decrypted_table_name1 ;
                      secret_column                       | decrypted_secret_column 
----------------------------------------------------------+-------------------------
 9ubE1JtNuXWxtslVDdzv68vFKUaiu7bponbkMaIcWmRujdv+mSZjD5g= | chuuuuuut
(1 row)

I don't understand either why you create the decrypted_table_name1 view yourself as pgsodium is supposed to build it for you.

That the decrypted view is not generated dynamically seems to be related with my supabase setup again. Some others had the same issue: supabase/supabase#11209. This might be an issue with the supabase version my project is built with. On a new project, pgsodium just works flawlessly - also the value update! Now I have to figure out how I can upgrade my project.

Thank you @ioguix