/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 2018 Couchbase, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LCB_CRYPTO_H #define LCB_CRYPTO_H /** * @file * Field encryption * * @uncommitted */ #ifdef __cplusplus extern "C" { #endif /** * @ingroup lcb-public-api * @defgroup lcb-crypto-api Encryption * @brief Register crypto-providers and working with encrypted fields of the documents. * @details * These routines contain functionality to define and hook crypto providers, as well as * functions which should be used for portable (cross SDK) encoding of encrypted fields. */ /** * @addtogroup lcb-crypto-api * @{ */ /** * IOV-style structure for signing functions of crypto-provider. * * @committed */ typedef struct lcbcrypto_SIGV { const uint8_t *data; /**< pointer to data */ size_t len; /**< length of the data in bytes */ } lcbcrypto_SIGV; struct lcbcrypto_PROVIDER; /** * Crypto-provider interface. * * See full example in @ref example/crypto/openssl_symmetric_provider.c * * @see lcbcrypto_register * @see lcbcrypto_unregister * * @committed */ typedef struct lcbcrypto_PROVIDER { uint16_t version; /**< version of the structure, current value is 1 */ int16_t _refcnt; /**< reference counter */ uint64_t flags; /**< provider-specific flags */ void *cookie; /**< opaque pointer (e.g. pointer to wrapper instance) */ void (*destructor)(struct lcbcrypto_PROVIDER *provider); /**< destructor function, or NULL */ union { LCB_DEPRECATED2( struct { void (*release_bytes)(struct lcbcrypto_PROVIDER * provider, void *bytes); lcb_error_t (*load_key)(struct lcbcrypto_PROVIDER * provider, lcbcrypto_KEYTYPE type, const char *keyid, uint8_t **key, size_t *key_len); lcb_error_t (*generate_iv)(struct lcbcrypto_PROVIDER * provider, uint8_t * *iv, size_t * iv_len); lcb_error_t (*sign)(struct lcbcrypto_PROVIDER * provider, const lcbcrypto_SIGV *inputs, size_t input_num, uint8_t **sig, size_t *sig_len); lcb_error_t (*verify_signature)(struct lcbcrypto_PROVIDER * provider, const lcbcrypto_SIGV *inputs, size_t input_num, uint8_t *sig, size_t sig_len); lcb_error_t (*encrypt)(struct lcbcrypto_PROVIDER * provider, const uint8_t *input, size_t input_len, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, uint8_t **output, size_t *output_len); lcb_error_t (*decrypt)(struct lcbcrypto_PROVIDER * provider, const uint8_t *input, size_t input_len, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, uint8_t **output, size_t *output_len); } v0, "v0 crypto API has been deprecated, use v1"); struct { /** function to use when the library wants to deallocate memory, returned by provider */ void (*release_bytes)(struct lcbcrypto_PROVIDER *provider, void *bytes); /** initialization vector (IV) generator */ lcb_error_t (*generate_iv)(struct lcbcrypto_PROVIDER *provider, uint8_t **iv, size_t *iv_len); /** generate cryptographic signature for the data */ lcb_error_t (*sign)(struct lcbcrypto_PROVIDER *provider, const lcbcrypto_SIGV *inputs, size_t input_num, uint8_t **sig, size_t *sig_len); /** verify signature of the data */ lcb_error_t (*verify_signature)(struct lcbcrypto_PROVIDER *provider, const lcbcrypto_SIGV *inputs, size_t input_num, uint8_t *sig, size_t sig_len); /** encrypt data */ lcb_error_t (*encrypt)(struct lcbcrypto_PROVIDER *provider, const uint8_t *input, size_t input_len, const uint8_t *iv, size_t iv_len, uint8_t **output, size_t *output_len); /** decrypt data */ lcb_error_t (*decrypt)(struct lcbcrypto_PROVIDER *provider, const uint8_t *input, size_t input_len, const uint8_t *iv, size_t iv_len, uint8_t **output, size_t *output_len); /** returns key identifier, associated with the crypto-provider */ const char *(*get_key_id)(struct lcbcrypto_PROVIDER *provider); } v1; } v; } lcbcrypto_PROVIDER; /** * Structure for JSON field specification for encrypt/decrypt API. * * @see lcbcrypto_encrypt_fields * @see lcbcrypto_decrypt_fields * * @committed */ typedef struct lcbcrypto_FIELDSPEC { const char *name; /**< field name (NUL-terminated) */ const char *alg; /**< crypto provider alias (NUL-terminated) */ LCB_DEPRECATED2(const char *kid, "Do not use kid field. Encryption keys have to be part of the provider implementation"); } lcbcrypto_FIELDSPEC; /** * Command to encrypt JSON fields. * * @see lcbcrypto_encrypt_fields * @committed */ typedef struct lcbcrypto_CMDENCRYPT { uint16_t version; /**< version of the structure, currently valid value is 0 */ const char *prefix; /**< prefix to encrypted field. When NULL, it will use @ref LCBCRYPTO_DEFAULT_FIELD_PREFIX */ const char *doc; /**< pointer to the input JSON document */ size_t ndoc; /**< size of the input JSON document */ char *out; /**< pointer to output JSON document. When no changes were applied, this field will be set to NULL */ size_t nout; /**< size of the output JSON document */ lcbcrypto_FIELDSPEC *fields; /**< list of field specs */ size_t nfields; /**< number of field specs */ } lcbcrypto_CMDENCRYPT; /** * Command to decrypt JSON fields. * * @see lcbcrypto_decrypt_fields * @committed */ typedef struct lcbcrypto_CMDDECRYPT { uint16_t version; /**< version of the structure, currently valid value is 0 */ const char *prefix; /**< prefix to encrypted field. When NULL, it will use @ref LCBCRYPTO_DEFAULT_FIELD_PREFIX */ const char *doc; /**< pointer to the input JSON document */ size_t ndoc; /**< size of the input JSON document */ char *out; /**< pointer to output JSON document. When no changes were applied, this field will be set to NULL */ size_t nout; /**< size of the output JSON document */ lcbcrypto_FIELDSPEC *fields; /**< list of field specs */ size_t nfields; /**< number of field specs */ } lcbcrypto_CMDDECRYPT; /** * Register crypto-provider for specified alias. * * See full example in @ref example/crypto/openssl_symmetric_provider.c * * @param instance the handle * @param name provider alias, this will be recorded in JSON. * @param provider implementation of the crypto-provider * * @par Register provider as "AES-256-HMAC-SHA256". * @code{.c} * lcbcrypto_PROVIDER *provider = calloc(1, sizeof(lcbcrypto_PROVIDER)); * provider->version = 1; * provider->destructor = osp_free; * provider->v.v1.release_bytes = osp_release_bytes; * provider->v.v1.generate_iv = osp_generate_iv; * provider->v.v1.sign = osp_sign; * provider->v.v1.verify_signature = osp_verify_signature; * provider->v.v1.encrypt = osp_encrypt; * provider->v.v1.decrypt = osp_decrypt; * provider->v.v1.get_key_id = osp_get_key_id; * lcbcrypto_register(instance, "AES-256-HMAC-SHA256", provider); * @endcode */ LIBCOUCHBASE_API void lcbcrypto_register(lcb_t instance, const char *name, lcbcrypto_PROVIDER *provider); /** * Unregister crypto-provider for specified alias. * * See full example in @ref example/crypto/openssl_symmetric_provider.c * * @param instance the handle * @param name provider alias. */ LIBCOUCHBASE_API void lcbcrypto_unregister(lcb_t instance, const char *name); /** * Increment reference counter for crypto-provider. * * @param provider provider instance */ LIBCOUCHBASE_API void lcbcrypto_ref(lcbcrypto_PROVIDER *provider); /** * Decrement reference counter for crypto-provider. * * It calls destructor once counter reaches zero. The provider instance should not be used after calling this function. * * @param provider provider instance */ LIBCOUCHBASE_API void lcbcrypto_unref(lcbcrypto_PROVIDER *provider); /** * Default prefix for encrypted JSON fields. */ #define LCBCRYPTO_DEFAULT_FIELD_PREFIX "__crypt_" /** * Encrypt all specified fields in the JSON encoded object. * * The function will remove original content of the field, and rename it using @ref LCBCRYPTO_DEFAULT_FIELD_PREFIX, or * custom prefix, specified in the command. * * See full example in @ref example/crypto/openssl_symmetric_encrypt.c * * @param instance the handle * @param cmd the command structure * @return LCB_SUCCESS if successful, an error code otherwise * * @par Encrypt field "message" in the document using provider registered as "AES-256-HMAC-SHA256" * @code{.c} * lcbcrypto_CMDENCRYPT cmd = {}; * lcbcrypto_FIELDSPEC field = {}; * lcb_error_t err; * * cmd.version = 0; * cmd.prefix = NULL; * cmd.doc = "{\"message\":\"hello world\"}"; * cmd.ndoc = strlen(cmd.doc); * cmd.nfields = 1; * cmd.fields = &field; * field.name = "message"; * field.alg = "AES-256-HMAC-SHA256"; * * err = lcbcrypto_encrypt_fields(instance, &cmd); * @endcode * * @committed */ LIBCOUCHBASE_API lcb_error_t lcbcrypto_encrypt_fields(lcb_t instance, lcbcrypto_CMDENCRYPT *cmd); /** * Decrypt all specified fields in the JSON encoded object. * * The function will remove original content of the field, and rename it using @ref LCBCRYPTO_DEFAULT_FIELD_PREFIX, or * custom prefix, specified in the command. * * See full example in @ref example/crypto/openssl_symmetric_decrypt.c * * @param instance the handle * @param cmd the command structure * @return LCB_SUCCESS if successful, an error code otherwise * * @par Decrypt field "message" in the document using provider registered as "AES-256-HMAC-SHA256" * @code{.c} * lcbcrypto_CMDDECRYPT cmd = {}; * lcbcrypto_FIELDSPEC field = {}; * lcb_error_t err; * * cmd.version = 0; * cmd.prefix = NULL; * cmd.doc = "{\"__crypt_message\":{" \ * "\"alg\":\"AES-256-HMAC-SHA256\"," \ * "\"ciphertext\":\"gYuyEhf6S0AiMGZJZZV35Q==\"," \ * "\"iv\":\"ZedmvjWy0lIrLn6OmQmNqQ==\"," \ * "\"kid\":\"mykeyid\"," \ * "\"sig\":\"FgleInW3Iia04XqLbm5Hd3qVoa77Ocs7g2x4pOutEtY=\"}" \ * "}"; * cmd.ndoc = strlen(cmd.doc); * cmd.nfields = 1; * cmd.fields = &field; * field.name = "message"; * field.alg = "AES-256-HMAC-SHA256"; * * err = lcbcrypto_decrypt_fields(instance, &cmd); * @endcode * * @committed */ LIBCOUCHBASE_API lcb_error_t lcbcrypto_decrypt_fields(lcb_t instance, lcbcrypto_CMDDECRYPT *cmd); /**@}*/ /** @deprecated Use @ref lcbcrypto_encrypt_fields() */ LCB_DEPR_API2(lcb_error_t lcbcrypto_encrypt_document(lcb_t instance, lcbcrypto_CMDENCRYPT *cmd), "Use lcbcrypto_encrypt_fields"); /** @deprecated Use @ref lcbcrypto_decrypt_fields() */ LCB_DEPR_API2(lcb_error_t lcbcrypto_decrypt_document(lcb_t instance, lcbcrypto_CMDDECRYPT *cmd), "Use lcbcrypto_decrypt_fields"); #ifdef __cplusplus } #endif #endif /* LCB_CRYPTO_H */