diff --git a/META.json b/META.json index 6bb7614..4ae972e 100644 --- a/META.json +++ b/META.json @@ -2,7 +2,7 @@ "name": "pgsodium", "abstract": "Postgres extension for libsodium functions", "description": "pgsodium is a PostgreSQL extension that exposes modern libsodium based cryptographic functions to SQL.", - "version": "3.0.3", + "version": "3.0.4", "maintainer": [ "Michel Pelletier " ], @@ -13,7 +13,7 @@ "abstract": "Postgres extension for libsodium functions", "file": "src/pgsodium.h", "docfile": "README.md", - "version": "3.0.3" + "version": "3.0.4" } }, "prereqs": { diff --git a/pgsodium.control b/pgsodium.control index 99dd93a..5b09a02 100644 --- a/pgsodium.control +++ b/pgsodium.control @@ -1,4 +1,4 @@ # pgsodium extension comment = 'Postgres extension for libsodium functions' -default_version = '3.0.3' +default_version = '3.0.4' relocatable = false diff --git a/sql/pgsodium--3.0.3--3.0.4.sql b/sql/pgsodium--3.0.3--3.0.4.sql new file mode 100644 index 0000000..6ec0905 --- /dev/null +++ b/sql/pgsodium--3.0.3--3.0.4.sql @@ -0,0 +1,88 @@ +CREATE OR REPLACE FUNCTION @extschema@.encrypted_columns( + relid OID +) +RETURNS TEXT AS +$$ +DECLARE + m RECORD; + expression TEXT; + comma TEXT; +BEGIN + expression := ''; + comma := E' '; + FOR m IN SELECT * FROM @extschema@.mask_columns(relid) LOOP + IF m.key_id IS NULL AND m.key_id_column is NULL THEN + CONTINUE; + ELSE + expression := expression || comma; + expression := expression || format( + $f$%s = pg_catalog.encode( + @extschema@.crypto_aead_det_encrypt( + pg_catalog.convert_to(%s, 'utf8'), + pg_catalog.convert_to(%s::text, 'utf8'), + %s::uuid, + %s + ), + 'base64')$f$, + 'new.' || quote_ident(m.attname), + 'new.' || quote_ident(m.attname), + COALESCE('new.' || quote_ident(m.associated_column), quote_literal('')), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + COALESCE('new.' || quote_ident(m.nonce_column), 'NULL') + ); + END IF; + comma := E';\n '; + END LOOP; + RETURN expression; +END +$$ + LANGUAGE plpgsql + VOLATILE + SET search_path='' + ; + +CREATE OR REPLACE FUNCTION @extschema@.decrypted_columns( + relid OID +) +RETURNS TEXT AS +$$ +DECLARE + m RECORD; + expression TEXT; + comma TEXT; + padding text = ' '; +BEGIN + expression := E'\n'; + comma := padding; + FOR m IN SELECT * FROM @extschema@.mask_columns(relid) LOOP + expression := expression || comma; + IF m.key_id IS NULL AND m.key_id_column IS NULL THEN + expression := expression || padding || quote_ident(m.attname); + ELSE + expression := expression || padding || quote_ident(m.attname) || E',\n'; + expression := expression || format( + $f$ + pg_catalog.convert_from( + @extschema@.crypto_aead_det_decrypt( + pg_catalog.decode(%s, 'base64'), + pg_catalog.convert_to(%s::text, 'utf8'), + %s::uuid, + %s + ), + 'utf8') AS %s$f$, + quote_ident(m.attname), + coalesce(quote_ident(m.associated_column), quote_literal('')), + coalesce(quote_ident(m.key_id_column), quote_literal(m.key_id)), + coalesce(quote_ident(m.nonce_column), 'NULL'), + 'decrypted_' || quote_ident(m.attname) + ); + END IF; + comma := E', \n'; + END LOOP; + RETURN expression; +END +$$ + LANGUAGE plpgsql + VOLATILE + SET search_path='' +; diff --git a/test/tce.sql b/test/tce.sql index 9303b64..65e2e70 100644 --- a/test/tce.sql +++ b/test/tce.sql @@ -18,8 +18,8 @@ CREATE TABLE private.foo( ); CREATE TABLE private.bar( + id bigserial primary key, secret text, - associated text, nonce bytea, secret2 text, associated2 text, @@ -52,7 +52,7 @@ SELECT lives_ok( SELECT lives_ok( format($test$ SECURITY LABEL FOR pgsodium ON COLUMN private.bar.secret - IS 'ENCRYPT WITH KEY ID %s ASSOCIATED associated NONCE nonce' + IS 'ENCRYPT WITH KEY ID %s ASSOCIATED id NONCE nonce' $test$, :'secret_key_id'), 'can label column for encryption'); @@ -61,6 +61,7 @@ CREATE ROLE bobo with login password 'foo'; GRANT USAGE ON SCHEMA private to bobo; GRANT SELECT ON TABLE private.foo to bobo; GRANT SELECT ON TABLE private.bar to bobo; +GRANT USAGE ON ALL SEQUENCES IN SCHEMA private TO bobo; SELECT lives_ok( $test$ @@ -96,8 +97,8 @@ SELECT lives_ok( SELECT lives_ok( format( $test$ - INSERT INTO bar (secret, associated, nonce, secret2, associated2, nonce2, secret2_key_id) - VALUES ('s3kr3t', 'alice was here', %L, 'shhh', 'bob was here', %L, %L::uuid); + INSERT INTO bar (secret, nonce, secret2, associated2, nonce2, secret2_key_id) + VALUES ('s3kr3t', %L, 'shhh', 'bob was here', %L, %L::uuid); $test$, :'nonce', :'nonce2',