Skip to content

Commit

Permalink
key derivation functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
michelp committed Jun 4, 2020
1 parent ad13616 commit 52b87d0
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 27 deletions.
2 changes: 1 addition & 1 deletion pgsodium.control
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pgsodium extension
comment = 'Postgres extension for libsodium functions'
default_version = '1.0.0'
default_version = '1.1.0'
relocatable = true
requires = ''
90 changes: 65 additions & 25 deletions src/pgsodium.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pgsodium_randombytes_buf(PG_FUNCTION_ARGS)
size_t size = PG_GETARG_UINT32(0);
unsigned long long result_size = VARHDRSZ + size;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
randombytes_buf(VARDATA(result), size);
PG_RETURN_BYTEA_P(result);
Expand All @@ -41,7 +41,7 @@ pgsodium_crypto_secretbox_keygen(PG_FUNCTION_ARGS)
{
unsigned long long result_size = VARHDRSZ + crypto_secretbox_KEYBYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
crypto_secretbox_keygen((unsigned char*)VARDATA(result));
PG_RETURN_BYTEA_P(result);
Expand All @@ -53,7 +53,7 @@ pgsodium_crypto_secretbox_noncegen(PG_FUNCTION_ARGS)
{
int result_size = VARHDRSZ + crypto_secretbox_NONCEBYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
randombytes_buf(VARDATA(result), crypto_secretbox_NONCEBYTES);
PG_RETURN_BYTEA_P(result);
Expand All @@ -69,7 +69,7 @@ pgsodium_crypto_secretbox(PG_FUNCTION_ARGS)
size_t message_size = crypto_secretbox_MACBYTES + VARSIZE_ANY_EXHDR(message);
unsigned long long result_size = VARHDRSZ + message_size;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

crypto_secretbox_easy(
Expand All @@ -93,7 +93,7 @@ pgsodium_crypto_secretbox_open(PG_FUNCTION_ARGS)
size_t message_size = VARSIZE_ANY_EXHDR(message) - crypto_secretbox_MACBYTES;
unsigned long long result_size = VARHDRSZ + message_size;
bytea *result = (bytea *) palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

success = crypto_secretbox_open_easy(
Expand All @@ -120,7 +120,7 @@ pgsodium_crypto_auth(PG_FUNCTION_ARGS)
bytea *key = PG_GETARG_BYTEA_P(1);
int result_size = VARHDRSZ + crypto_auth_BYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

crypto_auth(
Expand Down Expand Up @@ -154,7 +154,7 @@ pgsodium_crypto_auth_keygen(PG_FUNCTION_ARGS)
{
unsigned long long result_size = VARHDRSZ + crypto_auth_KEYBYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
crypto_secretbox_keygen((unsigned char*)VARDATA(result));
PG_RETURN_BYTEA_P(result);
Expand All @@ -181,7 +181,7 @@ pgsodium_crypto_generichash(PG_FUNCTION_ARGS)

result_size = VARHDRSZ + crypto_generichash_BYTES;
result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

crypto_generichash(
Expand Down Expand Up @@ -209,7 +209,7 @@ pgsodium_crypto_shorthash(PG_FUNCTION_ARGS)
PG_RETURN_NULL();

result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

crypto_shorthash(
Expand Down Expand Up @@ -241,9 +241,9 @@ pgsodium_crypto_box_keypair(PG_FUNCTION_ARGS)
"that cannot accept type record")));

publickey = (bytea*)palloc(public_size);
ZERO_BUFF_CB(publickey, public_size);
ZERO_BUFF_CB(publickey, public_size);
secretkey = (bytea*)palloc(secret_size);
ZERO_BUFF_CB(secretkey, secret_size);
ZERO_BUFF_CB(secretkey, secret_size);
SET_VARSIZE(publickey, public_size);
SET_VARSIZE(secretkey, secret_size);

Expand All @@ -265,7 +265,7 @@ pgsodium_crypto_box_noncegen(PG_FUNCTION_ARGS)
{
unsigned long long result_size = VARHDRSZ + crypto_box_NONCEBYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
randombytes_buf(VARDATA(result), crypto_box_NONCEBYTES);
PG_RETURN_BYTEA_P(result);
Expand All @@ -283,7 +283,7 @@ pgsodium_crypto_box(PG_FUNCTION_ARGS)

size_t message_size = crypto_box_MACBYTES + VARSIZE_ANY_EXHDR(message);
bytea *result = (bytea*)palloc(VARHDRSZ + message_size);
ZERO_BUFF_CB(result, VARHDRSZ + message_size);
ZERO_BUFF_CB(result, VARHDRSZ + message_size);
SET_VARSIZE(result, VARHDRSZ + message_size);
success = crypto_box_easy(
(unsigned char*)VARDATA(result),
Expand Down Expand Up @@ -314,7 +314,7 @@ pgsodium_crypto_box_open(PG_FUNCTION_ARGS)

size_t message_size = VARSIZE_ANY_EXHDR(message) - crypto_box_MACBYTES;
bytea *result = (bytea *) palloc(VARHDRSZ + message_size);
ZERO_BUFF_CB(result, VARHDRSZ + message_size);
ZERO_BUFF_CB(result, VARHDRSZ + message_size);
SET_VARSIZE(result, VARHDRSZ + message_size);
success = crypto_box_open_easy(
(unsigned char*)VARDATA(result),
Expand Down Expand Up @@ -352,9 +352,9 @@ pgsodium_crypto_sign_keypair(PG_FUNCTION_ARGS)
"that cannot accept type record")));

publickey = (bytea*)palloc(public_size);
ZERO_BUFF_CB(publickey, public_size);
ZERO_BUFF_CB(publickey, public_size);
secretkey = (bytea*)palloc(secret_size);
ZERO_BUFF_CB(secretkey, secret_size);
ZERO_BUFF_CB(secretkey, secret_size);
SET_VARSIZE(publickey, public_size);
SET_VARSIZE(secretkey, secret_size);

Expand All @@ -381,7 +381,7 @@ pgsodium_crypto_sign(PG_FUNCTION_ARGS)
size_t message_size = crypto_sign_BYTES + VARSIZE_ANY_EXHDR(message);
unsigned long long result_size = VARHDRSZ + message_size;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

success = crypto_sign(
Expand Down Expand Up @@ -410,7 +410,7 @@ pgsodium_crypto_sign_open(PG_FUNCTION_ARGS)
size_t message_size = VARSIZE_ANY_EXHDR(message) - crypto_sign_BYTES;
unsigned long long result_size = VARHDRSZ + message_size;
bytea *result = (bytea *) palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);

SET_VARSIZE(result, result_size);
success = crypto_sign_open(
Expand Down Expand Up @@ -438,7 +438,7 @@ pgsodium_crypto_sign_detached(PG_FUNCTION_ARGS)
size_t sig_size = crypto_sign_BYTES;
unsigned long long result_size = VARHDRSZ + sig_size;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

success = crypto_sign_detached(
Expand Down Expand Up @@ -471,7 +471,7 @@ pgsodium_crypto_sign_verify_detached(PG_FUNCTION_ARGS)
VARSIZE_ANY_EXHDR(message),
(unsigned char*)VARDATA(publickey)
);
if (success == 0)
if (success == 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
Expand All @@ -484,7 +484,7 @@ pgsodium_crypto_pwhash_saltgen(PG_FUNCTION_ARGS)
{
unsigned long long result_size = VARHDRSZ + crypto_pwhash_SALTBYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
randombytes_buf(VARDATA(result), crypto_pwhash_SALTBYTES);
PG_RETURN_BYTEA_P(result);
Expand All @@ -506,7 +506,7 @@ pgsodium_crypto_pwhash(PG_FUNCTION_ARGS)
PG_RETURN_NULL();

result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

success = crypto_pwhash(
Expand Down Expand Up @@ -534,7 +534,7 @@ pgsodium_crypto_pwhash_str(PG_FUNCTION_ARGS)
int success;
bytea *password = PG_GETARG_BYTEA_P(0);
bytea *result = (bytea *)palloc(crypto_pwhash_STRBYTES);
ZERO_BUFF_CB(result, crypto_pwhash_STRBYTES);
ZERO_BUFF_CB(result, crypto_pwhash_STRBYTES);
SET_VARSIZE(result, crypto_pwhash_STRBYTES);

success = crypto_pwhash_str(
Expand Down Expand Up @@ -577,7 +577,7 @@ pgsodium_crypto_box_seal(PG_FUNCTION_ARGS)
unsigned long long result_size = crypto_box_SEALBYTES + VARSIZE(message);

bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

crypto_box_seal(
Expand All @@ -599,7 +599,7 @@ pgsodium_crypto_box_seal_open(PG_FUNCTION_ARGS)

unsigned long long result_size = VARSIZE(ciphertext) - crypto_box_SEALBYTES;
bytea *result = (bytea *)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);

success = crypto_box_seal_open(
Expand All @@ -617,6 +617,46 @@ pgsodium_crypto_box_seal_open(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(result);
}

PG_FUNCTION_INFO_V1(pgsodium_crypto_kdf_keygen);
Datum
pgsodium_crypto_kdf_keygen(PG_FUNCTION_ARGS)
{
unsigned long long result_size = VARHDRSZ + crypto_kdf_KEYBYTES;
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);
SET_VARSIZE(result, result_size);
crypto_kdf_keygen((unsigned char*)VARDATA(result));
PG_RETURN_BYTEA_P(result);
}

PG_FUNCTION_INFO_V1(pgsodium_crypto_kdf_derive_from_key);
Datum
pgsodium_crypto_kdf_derive_from_key(PG_FUNCTION_ARGS)
{
size_t subkey_size = PG_GETARG_UINT32(0);
unsigned long long result_size = VARHDRSZ + subkey_size;
unsigned long long subkey_id = PG_GETARG_INT64(1);
bytea *context = PG_GETARG_BYTEA_P(2);
bytea *master_key = PG_GETARG_BYTEA_P(3);
bytea *result = (bytea*)palloc(result_size);
ZERO_BUFF_CB(result, result_size);

if (VARSIZE_ANY_EXHDR(context) != 8)
ereport(
ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("crypto_kdf_derive_from_key: context must be 8 bytes")));

SET_VARSIZE(result, result_size);
crypto_kdf_derive_from_key(
(unsigned char*)VARDATA(result),
subkey_size,
subkey_id,
(const char*)VARDATA(context),
(const unsigned char*)VARDATA(master_key));
PG_RETURN_BYTEA_P(result);
}

void _PG_init(void)
{
if (sodium_init() == -1)
Expand Down
5 changes: 5 additions & 0 deletions src/pgsodium.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@ Datum pgsodium_crypto_sign_open(PG_FUNCTION_ARGS);
Datum pgsodium_crypto_sign_detached(PG_FUNCTION_ARGS);
Datum pgsodium_crypto_sign_verify_detached(PG_FUNCTION_ARGS);

/* Key Derivation */

Datum pgsodium_crypto_kdf_keygen(PG_FUNCTION_ARGS);
Datum pgsodium_crypto_kdf_derive_from_key(PG_FUNCTION_ARGS);

#endif /* PGSODIUM_H */
17 changes: 16 additions & 1 deletion test.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ CREATE EXTENSION pgtap;
CREATE EXTENSION pgsodium;

BEGIN;
SELECT plan(23);
SELECT plan(26);

SELECT lives_ok($$SELECT randombytes_random()$$, 'randombytes_random');
SELECT lives_ok($$SELECT randombytes_uniform(10)$$, 'randombytes_uniform');
Expand Down Expand Up @@ -108,6 +108,20 @@ SELECT crypto_box('bob is your uncle', :'boxnonce', :'bob_public',
SELECT is(crypto_box_open(:'box', :'boxnonce', :'alice_public',
current_setting('app.bob_secret')::bytea),
'bob is your uncle', 'crypto_box_open');

SELECT crypto_kdf_keygen() kdfkey \gset
SELECT length(crypto_kdf_derive_from_key(64, 1, '__auth__', :'kdfkey')) kdfsubkeylen \gset
SELECT is(:kdfsubkeylen, 64, '64 byte derived subkey');

SELECT length(crypto_kdf_derive_from_key(32, 1, '__auth__', :'kdfkey')) kdfsubkeylen \gset
SELECT is(:kdfsubkeylen, 32, '32 byte derived subkey');

SELECT is(crypto_kdf_derive_from_key(32, 2, '__auth__', :'kdfkey'),
crypto_kdf_derive_from_key(32, 2, '__auth__', :'kdfkey'), 'subkeys are deterministic.');

SELECT throws_ok($$crypto_kdf_derive_from_key(32, 2, '__aut__', :'kdfkey')$$,
'kdf context not 8 bytes');

-- test relocatable schema

CREATE SCHEMA pgsodium;
Expand All @@ -118,5 +132,6 @@ SELECT lives_ok($$SELECT pgsodium.randombytes_random()$$, 'randombytes_random');
SELECT lives_ok($$SELECT pgsodium.randombytes_uniform(10)$$, 'randombytes_uniform');
SELECT lives_ok($$SELECT pgsodium.randombytes_buf(10)$$, 'randombytes_buf');


SELECT * FROM finish();
ROLLBACK;

0 comments on commit 52b87d0

Please sign in to comment.