write KYC attribute encryption logic

This commit is contained in:
Christian Grothoff 2022-12-31 15:10:35 +01:00
parent 509141b600
commit c5ad98da98
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 255 additions and 49 deletions

View File

@ -603,6 +603,19 @@ struct TALER_RefreshCommitmentP
}; };
/**
* Symmetric key we use to encrypt KYC attributes
* in our database.
*/
struct TALER_AttributeEncryptionKeyP
{
/**
* The key is a hash code.
*/
struct GNUNET_HashCode hash;
};
/** /**
* Token used for access control to the merchant's unclaimed * Token used for access control to the merchant's unclaimed
* orders. * orders.
@ -1791,6 +1804,37 @@ TALER_denom_pub_verify (const struct TALER_DenominationPublicKey *denom_pub,
const struct TALER_CoinPubHashP *c_hash); const struct TALER_CoinPubHashP *c_hash);
/**
* Encrypts KYC attributes for storage in the database.
*
* @param key encryption key to use
* @param attr set of attributes to encrypt
* @param[out] enc_attr encrypted attribute data
* @param[out] enc_attr_size number of bytes in @a enc_attr
*/
void
TALER_CRYPTO_kyc_attributes_encrypt (
const struct TALER_AttributeEncryptionKeyP *key,
const json_t *attr,
void **enc_attr,
size_t *enc_attr_size);
/**
* Encrypts KYC attributes for storage in the database.
*
* @param key encryption key to use
* @param enc_attr encrypted attribute data
* @param enc_attr_size number of bytes in @a enc_attr
* @return set of decrypted attributes, NULL on failure
*/
json_t *
TALER_CRYPTO_kyc_attributes_decrypt (
const struct TALER_AttributeEncryptionKeyP *key,
const void *enc_attr,
size_t enc_attr_size);
/** /**
* Check if a coin is valid; that is, whether the denomination key exists, * Check if a coin is valid; that is, whether the denomination key exists,
* is not expired, and the signature is correct. * is not expired, and the signature is correct.

View File

@ -109,7 +109,7 @@ derive_key (const void *key_material,
* @param[out] res_size size of the ciphertext * @param[out] res_size size of the ciphertext
*/ */
static void static void
contract_encrypt (const struct NonceP *nonce, blob_encrypt (const struct NonceP *nonce,
const void *key, const void *key,
size_t key_len, size_t key_len,
const void *data, const void *data,
@ -127,10 +127,13 @@ contract_encrypt (const struct NonceP *nonce,
salt, salt,
&skey); &skey);
ciphertext_size = crypto_secretbox_NONCEBYTES ciphertext_size = crypto_secretbox_NONCEBYTES
+ crypto_secretbox_MACBYTES + data_size; + crypto_secretbox_MACBYTES
+ data_size;
*res_size = ciphertext_size; *res_size = ciphertext_size;
*res = GNUNET_malloc (ciphertext_size); *res = GNUNET_malloc (ciphertext_size);
memcpy (*res, nonce, crypto_secretbox_NONCEBYTES); memcpy (*res,
nonce,
crypto_secretbox_NONCEBYTES);
GNUNET_assert (0 == GNUNET_assert (0 ==
crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES, crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
data, data,
@ -153,7 +156,7 @@ contract_encrypt (const struct NonceP *nonce,
* @return #GNUNET_OK on success * @return #GNUNET_OK on success
*/ */
static enum GNUNET_GenericReturnValue static enum GNUNET_GenericReturnValue
contract_decrypt (const void *key, blob_decrypt (const void *key,
size_t key_len, size_t key_len,
const void *data, const void *data,
size_t data_size, size_t data_size,
@ -278,7 +281,7 @@ TALER_CRYPTO_contract_encrypt_for_merge (
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&nonce, &nonce,
sizeof (nonce)); sizeof (nonce));
contract_encrypt (&nonce, blob_encrypt (&nonce,
&key, &key,
sizeof (key), sizeof (key),
hdr, hdr,
@ -316,7 +319,7 @@ TALER_CRYPTO_contract_decrypt_for_merge (
return NULL; return NULL;
} }
if (GNUNET_OK != if (GNUNET_OK !=
contract_decrypt (&key, blob_decrypt (&key,
sizeof (key), sizeof (key),
econtract, econtract,
econtract_size, econtract_size,
@ -407,6 +410,7 @@ TALER_CRYPTO_contract_encrypt_for_deposit (
&key)); &key));
cstr = json_dumps (contract_terms, cstr = json_dumps (contract_terms,
JSON_COMPACT | JSON_SORT_KEYS); JSON_COMPACT | JSON_SORT_KEYS);
GNUNET_assert (NULL != cstr);
clen = strlen (cstr); clen = strlen (cstr);
cbuf_size = compressBound (clen); cbuf_size = compressBound (clen);
xbuf = GNUNET_malloc (cbuf_size); xbuf = GNUNET_malloc (cbuf_size);
@ -426,7 +430,7 @@ TALER_CRYPTO_contract_encrypt_for_deposit (
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&nonce, &nonce,
sizeof (nonce)); sizeof (nonce));
contract_encrypt (&nonce, blob_encrypt (&nonce,
&key, &key,
sizeof (key), sizeof (key),
hdr, hdr,
@ -481,7 +485,7 @@ TALER_CRYPTO_contract_decrypt_for_deposit (
econtract += sizeof (*purse_pub); econtract += sizeof (*purse_pub);
econtract_size -= sizeof (*purse_pub); econtract_size -= sizeof (*purse_pub);
if (GNUNET_OK != if (GNUNET_OK !=
contract_decrypt (&key, blob_decrypt (&key,
sizeof (key), sizeof (key),
econtract, econtract,
econtract_size, econtract_size,
@ -538,3 +542,120 @@ TALER_CRYPTO_contract_decrypt_for_deposit (
GNUNET_free (cstr); GNUNET_free (cstr);
return ret; return ret;
} }
/**
* Salt we use when encrypting KYC attributes.
*/
#define ATTRIBUTE_SALT "kyc-attributes"
void
TALER_CRYPTO_kyc_attributes_encrypt (
const struct TALER_AttributeEncryptionKeyP *key,
const json_t *attr,
void **enc_attr,
size_t *enc_attr_size)
{
uLongf cbuf_size;
char *cstr;
uLongf clen;
void *xbuf;
int ret;
uint32_t belen;
struct NonceP nonce;
cstr = json_dumps (attr,
JSON_COMPACT | JSON_SORT_KEYS);
GNUNET_assert (NULL != cstr);
clen = strlen (cstr);
GNUNET_assert (clen <= UINT32_MAX);
cbuf_size = compressBound (clen);
xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t));
belen = htonl ((uint32_t) clen);
memcpy (xbuf,
&belen,
sizeof (belen));
ret = compress (xbuf + 4,
&cbuf_size,
(const Bytef *) cstr,
clen);
GNUNET_assert (Z_OK == ret);
free (cstr);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&nonce,
sizeof (nonce));
blob_encrypt (&nonce,
key,
sizeof (*key),
xbuf,
cbuf_size + sizeof (uint32_t),
ATTRIBUTE_SALT,
enc_attr,
enc_attr_size);
GNUNET_free (xbuf);
}
json_t *
TALER_CRYPTO_kyc_attributes_decrypt (
const struct TALER_AttributeEncryptionKeyP *key,
const void *enc_attr,
size_t enc_attr_size)
{
void *xhdr;
size_t hdr_size;
char *cstr;
uLongf clen;
json_error_t json_error;
json_t *ret;
uint32_t belen;
if (GNUNET_OK !=
blob_decrypt (key,
sizeof (*key),
enc_attr,
enc_attr_size,
ATTRIBUTE_SALT,
&xhdr,
&hdr_size))
{
GNUNET_break_op (0);
return NULL;
}
memcpy (&belen,
xhdr,
sizeof (belen));
clen = ntohl (belen);
if (clen >= GNUNET_MAX_MALLOC_CHECKED)
{
GNUNET_break_op (0);
GNUNET_free (xhdr);
return NULL;
}
cstr = GNUNET_malloc (clen + 1);
if (Z_OK !=
uncompress ((Bytef *) cstr,
&clen,
(const Bytef *) (xhdr + sizeof (uint32_t)),
hdr_size - sizeof (uint32_t)))
{
GNUNET_break_op (0);
GNUNET_free (cstr);
GNUNET_free (xhdr);
return NULL;
}
GNUNET_free (xhdr);
ret = json_loadb ((char *) cstr,
clen,
JSON_DECODE_ANY,
&json_error);
if (NULL == ret)
{
GNUNET_break_op (0);
GNUNET_free (cstr);
return NULL;
}
GNUNET_free (cstr);
return ret;
}

View File

@ -150,12 +150,12 @@ test_planchets_rsa (uint8_t age)
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
&ps, &ps,
sizeof (ps)); sizeof (ps));
GNUNET_log_skip (1, GNUNET_YES);
GNUNET_assert (GNUNET_SYSERR == GNUNET_assert (GNUNET_SYSERR ==
TALER_denom_priv_create (&dk_priv, TALER_denom_priv_create (&dk_priv,
&dk_pub, &dk_pub,
TALER_DENOMINATION_INVALID)); TALER_DENOMINATION_INVALID));
GNUNET_log_skip (1, GNUNET_YES);
GNUNET_assert (GNUNET_SYSERR == GNUNET_assert (GNUNET_SYSERR ==
TALER_denom_priv_create (&dk_priv, TALER_denom_priv_create (&dk_priv,
&dk_pub, &dk_pub,
@ -481,12 +481,51 @@ test_contracts (void)
} }
static int
test_attributes (void)
{
struct TALER_AttributeEncryptionKeyP key;
void *eattr;
size_t eattr_size;
json_t *c;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&key,
sizeof (key));
c = json_pack ("{s:s}", "test", "value");
GNUNET_assert (NULL != c);
TALER_CRYPTO_kyc_attributes_encrypt (&key,
c,
&eattr,
&eattr_size);
json_decref (c);
c = TALER_CRYPTO_kyc_attributes_decrypt (&key,
eattr,
eattr_size);
GNUNET_free (eattr);
if (NULL == c)
{
GNUNET_break (0);
return 1;
}
GNUNET_assert (0 ==
strcmp ("value",
json_string_value (json_object_get (c,
"test"))));
json_decref (c);
return 0;
}
int int
main (int argc, main (int argc,
const char *const argv[]) const char *const argv[])
{ {
(void) argc; (void) argc;
(void) argv; (void) argv;
GNUNET_log_setup ("test-crypto",
"WARNING",
NULL);
if (0 != test_high_level ()) if (0 != test_high_level ())
return 1; return 1;
if (0 != test_planchets (0)) if (0 != test_planchets (0))
@ -499,6 +538,8 @@ main (int argc,
return 5; return 5;
if (0 != test_contracts ()) if (0 != test_contracts ())
return 6; return 6;
if (0 != test_attributes ())
return 7;
return 0; return 0;
} }