aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_contract.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_contract.c')
-rw-r--r--src/util/crypto_contract.c300
1 files changed, 298 insertions, 2 deletions
diff --git a/src/util/crypto_contract.c b/src/util/crypto_contract.c
index 7f684d80a..5117712ea 100644
--- a/src/util/crypto_contract.c
+++ b/src/util/crypto_contract.c
@@ -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;
}