-first cut at contract encryption and decryption
This commit is contained in:
parent
ee4077ef80
commit
a227ee6d1b
@ -4287,6 +4287,9 @@ struct TALER_EXCHANGE_PurseDeposit
|
||||
* @param purse_expiration when will the unmerged purse expire
|
||||
* @param num_deposits length of the @a deposits array
|
||||
* @param deposits array of deposits to make into the purse
|
||||
* @param upload_contract true to upload the contract; must
|
||||
* be FALSE for repeated calls to this API for the
|
||||
* same purse (i.e. when adding more deposits).
|
||||
* @param cb function to call with the exchange's result
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return the request handle; NULL upon error
|
||||
@ -4301,6 +4304,7 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
||||
struct GNUNET_TIME_Timestamp purse_expiration,
|
||||
unsigned int num_deposits,
|
||||
const struct TALER_EXCHANGE_PurseDeposit *deposits,
|
||||
bool upload_contract,
|
||||
TALER_EXCHANGE_PurseCreateDepositCallback cb,
|
||||
void *cb_cls);
|
||||
|
||||
|
@ -202,6 +202,7 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
||||
struct GNUNET_TIME_Timestamp purse_expiration,
|
||||
unsigned int num_deposits,
|
||||
const struct TALER_EXCHANGE_PurseDeposit *deposits,
|
||||
bool upload_contract,
|
||||
TALER_EXCHANGE_PurseCreateDepositCallback cb,
|
||||
void *cb_cls)
|
||||
{
|
||||
@ -335,23 +336,25 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
||||
}
|
||||
GNUNET_free (url);
|
||||
{
|
||||
void *econtract;
|
||||
size_t econtract_size;
|
||||
void *econtract = NULL;
|
||||
size_t econtract_size = 0;
|
||||
|
||||
TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
|
||||
contract_priv,
|
||||
merge_priv,
|
||||
contract_terms,
|
||||
&econtract,
|
||||
&econtract_size);
|
||||
if (upload_contract)
|
||||
TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
|
||||
contract_priv,
|
||||
merge_priv,
|
||||
contract_terms,
|
||||
&econtract,
|
||||
&econtract_size);
|
||||
create_obj = GNUNET_JSON_PACK (
|
||||
TALER_JSON_pack_amount ("amount",
|
||||
&purse_value_after_fees),
|
||||
GNUNET_JSON_pack_uint64 ("min_age",
|
||||
min_age),
|
||||
GNUNET_JSON_pack_data_varsize ("econtract",
|
||||
econtract,
|
||||
econtract_size),
|
||||
GNUNET_JSON_pack_allow_null (
|
||||
GNUNET_JSON_pack_data_varsize ("econtract",
|
||||
econtract,
|
||||
econtract_size)),
|
||||
GNUNET_JSON_pack_data_auto ("contract_pub",
|
||||
&contract_pub),
|
||||
GNUNET_JSON_pack_data_auto ("merge_pub",
|
||||
|
@ -105,8 +105,11 @@ libtalerutil_la_SOURCES = \
|
||||
|
||||
libtalerutil_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
-lsodium \
|
||||
-ljansson \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
-lmicrohttpd $(XLIB) \
|
||||
-lz \
|
||||
-lm
|
||||
|
||||
libtalerutil_la_LDFLAGS = \
|
||||
|
@ -20,6 +20,191 @@
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include <zlib.h>
|
||||
#include "taler_exchange_service.h"
|
||||
|
||||
|
||||
/**
|
||||
* Nonce used for encryption, 24 bytes.
|
||||
*/
|
||||
struct NonceP
|
||||
{
|
||||
uint8_t nonce[crypto_secretbox_NONCEBYTES];
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies a key used for symmetric encryption, 32 bytes.
|
||||
*/
|
||||
struct SymKeyP
|
||||
{
|
||||
uint32_t key[8];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compute @a key.
|
||||
*
|
||||
* @param key_material key for calculation
|
||||
* @param key_m_len length of key
|
||||
* @param nonce nonce for calculation
|
||||
* @param salt salt value for calculation
|
||||
* @param[out] key where to write the en-/description key
|
||||
*/
|
||||
static void
|
||||
derive_key (const void *key_material,
|
||||
size_t key_m_len,
|
||||
const struct NonceP *nonce,
|
||||
const char *salt,
|
||||
struct SymKeyP *key)
|
||||
{
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
GNUNET_CRYPTO_kdf (key,
|
||||
sizeof (*key),
|
||||
/* salt / XTS */
|
||||
nonce,
|
||||
sizeof (*nonce),
|
||||
/* ikm */
|
||||
key_material,
|
||||
key_m_len,
|
||||
/* info chunks */
|
||||
/* The "salt" passed here is actually not something random,
|
||||
but a protocol-specific identifier string. Thus
|
||||
we pass it as a context info to the HKDF */
|
||||
salt,
|
||||
strlen (salt),
|
||||
NULL,
|
||||
0));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encryption of data.
|
||||
*
|
||||
* @param nonce value to use for the nonce
|
||||
* @param key key which is used to derive a key/iv pair from
|
||||
* @param key_len length of key
|
||||
* @param data data to encrypt
|
||||
* @param data_size size of the data
|
||||
* @param salt salt value which is used for key derivation
|
||||
* @param[out] res ciphertext output
|
||||
* @param[out] res_size size of the ciphertext
|
||||
*/
|
||||
static void
|
||||
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;
|
||||
|
||||
derive_key (key,
|
||||
key_len,
|
||||
nonce,
|
||||
salt,
|
||||
&skey);
|
||||
ciphertext_size = crypto_secretbox_NONCEBYTES
|
||||
+ crypto_secretbox_MACBYTES + data_size;
|
||||
*res_size = ciphertext_size;
|
||||
*res = GNUNET_malloc (ciphertext_size);
|
||||
memcpy (*res, nonce, crypto_secretbox_NONCEBYTES);
|
||||
GNUNET_assert (0 ==
|
||||
crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
|
||||
data,
|
||||
data_size,
|
||||
(void *) nonce,
|
||||
(void *) &skey));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decryption of data like encrypted recovery document etc.
|
||||
*
|
||||
* @param key key which is used to derive a key/iv pair from
|
||||
* @param key_len length of key
|
||||
* @param data data to decrypt
|
||||
* @param data_size size of the data
|
||||
* @param salt salt value which is used for key derivation
|
||||
* @param[out] res plaintext output
|
||||
* @param[out] res_size size of the plaintext
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
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;
|
||||
size_t plaintext_size;
|
||||
|
||||
if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
nonce = data;
|
||||
derive_key (key,
|
||||
key_len,
|
||||
nonce,
|
||||
salt,
|
||||
&skey);
|
||||
plaintext_size = data_size - (crypto_secretbox_NONCEBYTES
|
||||
+ crypto_secretbox_MACBYTES);
|
||||
*res = GNUNET_malloc (plaintext_size);
|
||||
*res_size = plaintext_size;
|
||||
if (0 != crypto_secretbox_open_easy (*res,
|
||||
data + crypto_secretbox_NONCEBYTES,
|
||||
data_size - crypto_secretbox_NONCEBYTES,
|
||||
(void *) nonce,
|
||||
(void *) &skey))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (*res);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Header for encrypted contracts.
|
||||
*/
|
||||
struct ContractHeader
|
||||
{
|
||||
/**
|
||||
* Type of the contract, in NBO.
|
||||
*/
|
||||
uint32_t ctype;
|
||||
|
||||
/**
|
||||
* Length of the encrypted contract, in NBO.
|
||||
*/
|
||||
uint32_t clen;
|
||||
|
||||
/**
|
||||
* Included key material, depending on @e ctype.
|
||||
*/
|
||||
union
|
||||
{
|
||||
struct TALER_PurseMergePrivateKeyP merge_priv;
|
||||
} keys;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Salt we use when encrypting contracts for merge.
|
||||
*/
|
||||
#define MERGE_SALT "p2p-merge-contract"
|
||||
|
||||
|
||||
void
|
||||
@ -29,9 +214,52 @@ TALER_CRYPTO_contract_encrypt_for_merge (
|
||||
const struct TALER_PurseMergePrivateKeyP *merge_priv,
|
||||
const json_t *contract_terms,
|
||||
void **econtract,
|
||||
|
||||
size_t *econtract_size)
|
||||
{
|
||||
struct GNUNET_HashCode key;
|
||||
char *cstr;
|
||||
size_t clen;
|
||||
void *xbuf;
|
||||
struct ContractHeader *hdr;
|
||||
struct NonceP nonce;
|
||||
uLongf cbuf_size;
|
||||
int ret;
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
|
||||
&purse_pub->eddsa_pub,
|
||||
&key));
|
||||
cstr = json_dumps (contract_terms,
|
||||
JSON_COMPACT | JSON_SORT_KEYS);
|
||||
clen = strlen (cstr);
|
||||
cbuf_size = compressBound (clen);
|
||||
xbuf = GNUNET_malloc (cbuf_size);
|
||||
ret = compress (xbuf,
|
||||
&cbuf_size,
|
||||
(const Bytef *) cstr,
|
||||
clen);
|
||||
GNUNET_assert (Z_OK == ret);
|
||||
free (cstr);
|
||||
hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size);
|
||||
hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER);
|
||||
hdr->clen = htonl ((uint32_t) clen);
|
||||
hdr->keys.merge_priv = *merge_priv;
|
||||
memcpy (&hdr[1],
|
||||
xbuf,
|
||||
cbuf_size);
|
||||
GNUNET_free (xbuf);
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
|
||||
&nonce,
|
||||
sizeof (nonce));
|
||||
encrypt (&nonce,
|
||||
&key,
|
||||
sizeof (key),
|
||||
hdr,
|
||||
sizeof (*hdr) + cbuf_size,
|
||||
MERGE_SALT,
|
||||
econtract,
|
||||
econtract_size);
|
||||
GNUNET_free (hdr);
|
||||
}
|
||||
|
||||
|
||||
@ -43,5 +271,73 @@ TALER_CRYPTO_contract_decrypt_for_merge (
|
||||
size_t econtract_size,
|
||||
struct TALER_PurseMergePrivateKeyP *merge_priv)
|
||||
{
|
||||
return NULL;
|
||||
struct GNUNET_HashCode key;
|
||||
void *xhdr;
|
||||
size_t hdr_size;
|
||||
const struct ContractHeader *hdr;
|
||||
char *cstr;
|
||||
uLongf clen;
|
||||
json_error_t json_error;
|
||||
json_t *ret;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
|
||||
&purse_pub->eddsa_pub,
|
||||
&key))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
decrypt (&key,
|
||||
sizeof (key),
|
||||
econtract,
|
||||
econtract_size,
|
||||
MERGE_SALT,
|
||||
&xhdr,
|
||||
&hdr_size))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return NULL;
|
||||
}
|
||||
if (hdr_size < sizeof (*hdr))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_free (xhdr);
|
||||
return NULL;
|
||||
}
|
||||
hdr = xhdr;
|
||||
clen = ntohl (hdr->clen);
|
||||
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 *) &hdr[1],
|
||||
hdr_size - sizeof (*hdr)))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_free (cstr);
|
||||
GNUNET_free (xhdr);
|
||||
return NULL;
|
||||
}
|
||||
*merge_priv = hdr->keys.merge_priv;
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user