diff options
| author | Christian Grothoff <christian@grothoff.org> | 2022-12-31 15:10:35 +0100 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2022-12-31 15:10:35 +0100 | 
| commit | c5ad98da9812a05d078b6b017a545959ada96a3d (patch) | |
| tree | 8126e2ea4ca56a3f86287cf21730777371cf5dc3 /src | |
| parent | 509141b6002d49db5a92b6d573cc7cca237fc1f0 (diff) | |
write KYC attribute encryption logic
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/taler_crypto_lib.h | 44 | ||||
| -rw-r--r-- | src/util/crypto_contract.c | 215 | ||||
| -rw-r--r-- | src/util/test_crypto.c | 45 | 
3 files changed, 255 insertions, 49 deletions
| diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 5e7ea605..ca80c6cc 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -604,6 +604,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   * orders.   */ @@ -1792,6 +1805,37 @@ TALER_denom_pub_verify (const struct TALER_DenominationPublicKey *denom_pub,  /** + * 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,   * is not expired, and the signature is correct.   * diff --git a/src/util/crypto_contract.c b/src/util/crypto_contract.c index fe6b1e6a..3bfe9eb8 100644 --- a/src/util/crypto_contract.c +++ b/src/util/crypto_contract.c @@ -109,14 +109,14 @@ derive_key (const void *key_material,   * @param[out] res_size size of the ciphertext   */  static void -contract_encrypt (const struct NonceP *nonce, -                  const void *key, -                  size_t key_len, -                  const void *data, -                  size_t data_size, -                  const char *salt, -                  void **res, -                  size_t *res_size) +blob_encrypt (const struct NonceP *nonce, +              const void *key, +              size_t key_len, +              const void *data, +              size_t data_size, +              const char *salt, +              void **res, +              size_t *res_size)  {    size_t ciphertext_size;    struct SymKeyP skey; @@ -127,10 +127,13 @@ contract_encrypt (const struct NonceP *nonce,                salt,                &skey);    ciphertext_size = crypto_secretbox_NONCEBYTES -                    + crypto_secretbox_MACBYTES + data_size; +                    + crypto_secretbox_MACBYTES +                    + data_size;    *res_size = ciphertext_size;    *res = GNUNET_malloc (ciphertext_size); -  memcpy (*res, nonce, crypto_secretbox_NONCEBYTES); +  memcpy (*res, +          nonce, +          crypto_secretbox_NONCEBYTES);    GNUNET_assert (0 ==                   crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,                                          data, @@ -153,13 +156,13 @@ contract_encrypt (const struct NonceP *nonce,   * @return #GNUNET_OK on success   */  static enum GNUNET_GenericReturnValue -contract_decrypt (const void *key, -                  size_t key_len, -                  const void *data, -                  size_t data_size, -                  const char *salt, -                  void **res, -                  size_t *res_size) +blob_decrypt (const void *key, +              size_t key_len, +              const void *data, +              size_t data_size, +              const char *salt, +              void **res, +              size_t *res_size)  {    const struct NonceP *nonce;    struct SymKeyP skey; @@ -278,14 +281,14 @@ TALER_CRYPTO_contract_encrypt_for_merge (    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,                                &nonce,                                sizeof (nonce)); -  contract_encrypt (&nonce, -                    &key, -                    sizeof (key), -                    hdr, -                    sizeof (*hdr) + cbuf_size, -                    MERGE_SALT, -                    econtract, -                    econtract_size); +  blob_encrypt (&nonce, +                &key, +                sizeof (key), +                hdr, +                sizeof (*hdr) + cbuf_size, +                MERGE_SALT, +                econtract, +                econtract_size);    GNUNET_free (hdr);  } @@ -316,13 +319,13 @@ TALER_CRYPTO_contract_decrypt_for_merge (      return NULL;    }    if (GNUNET_OK != -      contract_decrypt (&key, -                        sizeof (key), -                        econtract, -                        econtract_size, -                        MERGE_SALT, -                        &xhdr, -                        &hdr_size)) +      blob_decrypt (&key, +                    sizeof (key), +                    econtract, +                    econtract_size, +                    MERGE_SALT, +                    &xhdr, +                    &hdr_size))    {      GNUNET_break_op (0);      return NULL; @@ -407,6 +410,7 @@ TALER_CRYPTO_contract_encrypt_for_deposit (                                             &key));    cstr = json_dumps (contract_terms,                       JSON_COMPACT | JSON_SORT_KEYS); +  GNUNET_assert (NULL != cstr);    clen = strlen (cstr);    cbuf_size = compressBound (clen);    xbuf = GNUNET_malloc (cbuf_size); @@ -426,14 +430,14 @@ TALER_CRYPTO_contract_encrypt_for_deposit (    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,                                &nonce,                                sizeof (nonce)); -  contract_encrypt (&nonce, -                    &key, -                    sizeof (key), -                    hdr, -                    sizeof (*hdr) + cbuf_size, -                    DEPOSIT_SALT, -                    &xecontract, -                    &xecontract_size); +  blob_encrypt (&nonce, +                &key, +                sizeof (key), +                hdr, +                sizeof (*hdr) + cbuf_size, +                DEPOSIT_SALT, +                &xecontract, +                &xecontract_size);    GNUNET_free (hdr);    /* prepend purse_pub */    *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub)); @@ -481,13 +485,13 @@ TALER_CRYPTO_contract_decrypt_for_deposit (    econtract += sizeof (*purse_pub);    econtract_size -= sizeof (*purse_pub);    if (GNUNET_OK != -      contract_decrypt (&key, -                        sizeof (key), -                        econtract, -                        econtract_size, -                        DEPOSIT_SALT, -                        &xhdr, -                        &hdr_size)) +      blob_decrypt (&key, +                    sizeof (key), +                    econtract, +                    econtract_size, +                    DEPOSIT_SALT, +                    &xhdr, +                    &hdr_size))    {      GNUNET_break_op (0);      return NULL; @@ -538,3 +542,120 @@ TALER_CRYPTO_contract_decrypt_for_deposit (    GNUNET_free (cstr);    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; +} diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c index ce4181ff..b1c3c8e8 100644 --- a/src/util/test_crypto.c +++ b/src/util/test_crypto.c @@ -150,12 +150,12 @@ test_planchets_rsa (uint8_t age)    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,                                &ps,                                sizeof (ps)); - +  GNUNET_log_skip (1, GNUNET_YES);    GNUNET_assert (GNUNET_SYSERR ==                   TALER_denom_priv_create (&dk_priv,                                            &dk_pub,                                            TALER_DENOMINATION_INVALID)); - +  GNUNET_log_skip (1, GNUNET_YES);    GNUNET_assert (GNUNET_SYSERR ==                   TALER_denom_priv_create (&dk_priv,                                            &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  main (int argc,        const char *const argv[])  {    (void) argc;    (void) argv; +  GNUNET_log_setup ("test-crypto", +                    "WARNING", +                    NULL);    if (0 != test_high_level ())      return 1;    if (0 != test_planchets (0)) @@ -499,6 +538,8 @@ main (int argc,      return 5;    if (0 != test_contracts ())      return 6; +  if (0 != test_attributes ()) +    return 7;    return 0;  } | 
