#include <errno.h>
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
#include <sodium.h>
#define CHECK_LEN crypto_aead_xchacha20poly1305_ietf_ABYTES
#define KEY_LEN crypto_aead_xchacha20poly1305_ietf_KEYBYTES
#define NONCE_LEN crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
#define HEADER_BYTE_FORMATVERSION 0
#define HEADER_BYTE_CONSTRUCTION 1
#define HEADER_BYTE_ZERO_0 2
#define HEADER_BYTE_ZERO_1 3
#define HEADER_LEN 4
#define ONDISK_CIPHER_XCHACHA20POLY1305 1
#define ONDISK_VERSION_CURRENT 1
#define HEADER_LOCATION 0
#define NONCE_LOCATION HEADER_LEN
#define CIPHERTEXT_LOCATION (HEADER_LEN + NONCE_LEN)
typedef struct {
uint8_t *secretkey;
} SODIUM_ENCRYPTOR;
static int
sodium_error(SODIUM_ENCRYPTOR *encryptor,
WT_SESSION *session,
int err,
const char *msg)
{
wt_api = encryptor->wt_api;
wt_api, session,
"sodium encryption: %s: %s", msg, wt_api->
strerror(wt_api, NULL, err));
return (err);
}
static void
create_nonce(uint8_t *dst, size_t len)
{
randombytes_buf(dst, len);
}
static int
uint8_t *ciphertext, size_t cipher_maxlen, size_t *result_lenp)
{
SODIUM_ENCRYPTOR *sodium_encryptor = (SODIUM_ENCRYPTOR *)encryptor;
unsigned long long cipher_len;
int ret;
(void)session;
if (cipher_maxlen < HEADER_LEN + NONCE_LEN + clear_len + CHECK_LEN)
return (sodium_error(sodium_encryptor, session, ENOMEM, "encrypt buffer not big enough"));
ciphertext[HEADER_LOCATION + HEADER_BYTE_FORMATVERSION] = ONDISK_VERSION_CURRENT;
ciphertext[HEADER_LOCATION + HEADER_BYTE_CONSTRUCTION] = ONDISK_CIPHER_XCHACHA20POLY1305;
ciphertext[HEADER_LOCATION + HEADER_BYTE_ZERO_0] = 0;
ciphertext[HEADER_LOCATION + HEADER_BYTE_ZERO_1] = 0;
create_nonce(&ciphertext[NONCE_LOCATION], NONCE_LEN);
ret = crypto_aead_xchacha20poly1305_ietf_encrypt(&ciphertext[CIPHERTEXT_LOCATION], &cipher_len,
cleartext, clear_len, &ciphertext[HEADER_LOCATION], HEADER_LEN, NULL,
&ciphertext[NONCE_LOCATION], sodium_encryptor->secretkey);
if (ret < 0)
return (sodium_error(sodium_encryptor, session,
WT_ERROR,
"encryption failed"));
*result_lenp = HEADER_LEN + NONCE_LEN + cipher_len;
return (0);
}
static int
uint8_t *cleartext, size_t clear_maxlen, size_t *result_lenp)
{
SODIUM_ENCRYPTOR *sodium_encryptor = (SODIUM_ENCRYPTOR *)encryptor;
size_t cipher_check_only_len;
unsigned long long clear_len;
int ret;
if (HEADER_LEN + NONCE_LEN + clear_maxlen + CHECK_LEN < cipher_len)
return (sodium_error(sodium_encryptor, session, ENOMEM, "decrypt buffer not big enough"));
cipher_check_only_len = cipher_len - HEADER_LEN - NONCE_LEN;
ret = crypto_aead_xchacha20poly1305_ietf_decrypt(cleartext, &clear_len, NULL,
&ciphertext[CIPHERTEXT_LOCATION], cipher_check_only_len, &ciphertext[HEADER_LOCATION],
HEADER_LEN, &ciphertext[NONCE_LOCATION], sodium_encryptor->secretkey);
if (ret < 0)
return (sodium_error(sodium_encryptor, session,
WT_ERROR,
"decryption failed"));
*result_lenp = clear_len;
return (0);
}
static int
{
(void)encryptor;
(void)session;
*expansion_constantp = HEADER_LEN + NONCE_LEN + CHECK_LEN;
return (0);
}
static int
{
const SODIUM_ENCRYPTOR *orig;
SODIUM_ENCRYPTOR *new;
size_t keylen;
int ret;
orig = (const SODIUM_ENCRYPTOR *)encryptor;
wt_api = orig->wt_api;
if ((new = calloc(1, sizeof(*new))) == NULL)
return (errno);
*new = *orig;
new->secretkey = NULL;
ret = wt_api->
config_get(wt_api, session, encrypt_config,
"keyid", &keyid);
if (ret != 0)
ret = wt_api->
config_get(wt_api, session, encrypt_config,
"secretkey", &secretkey);
if (ret != 0)
if (keyid.
len != 0 && secretkey.
len != 0) {
ret = sodium_error(
new, NULL, EINVAL, "sodium_customize: keys specified with both keyid= and secretkey=");
goto err;
}
if (keyid.
len == 0 && secretkey.
len == 0) {
ret = sodium_error(
new, NULL, EINVAL, "sodium_customize: no key given with either keyid= or secretkey=");
goto err;
}
new->secretkey = sodium_malloc(KEY_LEN);
if (new->secretkey == NULL) {
ret = errno;
goto err;
}
ret = sodium_error(new, NULL, EINVAL, "sodium_customize: keyids not supported yet");
goto err;
}
if (secretkey.
len != 0) {
ret = sodium_hex2bin(
new->secretkey, KEY_LEN, secretkey.
str, secretkey.
len, NULL, &keylen, NULL);
if (ret < 0) {
ret = sodium_error(new, NULL, EINVAL, "sodium_customize: secret key not hex");
goto err;
}
if (keylen != KEY_LEN) {
ret = sodium_error(new, NULL, EINVAL, "sodium_customize: wrong secret key length");
goto err;
}
}
return (0);
err:
sodium_free(new->secretkey);
free(new);
return (ret);
}
static int
{
SODIUM_ENCRYPTOR *sodium_encryptor = (SODIUM_ENCRYPTOR *)encryptor;
(void)session;
randombytes_close();
sodium_free(sodium_encryptor->secretkey);
free(sodium_encryptor);
return (0);
}
static int
sodium_configure(SODIUM_ENCRYPTOR *sodium_encryptor,
WT_CONFIG_ARG *config)
{
wt_api = sodium_encryptor->wt_api;
(void)config;
(void)wt_api;
return (0);
}
int
{
SODIUM_ENCRYPTOR *sodium_encryptor;
int ret;
if ((sodium_encryptor = calloc(1, sizeof(SODIUM_ENCRYPTOR))) == NULL)
return (errno);
sodium_encryptor->encryptor.encrypt = sodium_encrypt;
sodium_encryptor->encryptor.decrypt = sodium_decrypt;
sodium_encryptor->encryptor.sizing = sodium_sizing;
sodium_encryptor->encryptor.customize = sodium_customize;
sodium_encryptor->encryptor.terminate = sodium_terminate;
if (sodium_init() < 0)
if ((ret = sodium_configure(sodium_encryptor, config)) != 0) {
free(sodium_encryptor);
return (ret);
}
connection,
"sodium", (
WT_ENCRYPTOR *)sodium_encryptor, NULL)) != 0) {
free(sodium_encryptor);
return (ret);
}
return (0);
}
int(* config_get)(WT_EXTENSION_API *wt_api, WT_SESSION *session, WT_CONFIG_ARG *config, const char *key, WT_CONFIG_ITEM *value)
Return the value of a configuration key.
Definition wiredtiger_ext.h:184
const char *(* strerror)(WT_EXTENSION_API *, WT_SESSION *session, int error)
Return information about an error as a string.
Definition wiredtiger_ext.h:100
int(* err_printf)(WT_EXTENSION_API *wt_api, WT_SESSION *session, const char *fmt,...)
Insert an error message into the WiredTiger error stream.
Definition wiredtiger_ext.h:76
int wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
Entry point to an extension, called when the extension is loaded.
struct WT_CONFIG_ARG WT_CONFIG_ARG
A configuration object passed to some extension interfaces.
Definition wiredtiger.in:4204
The interface implemented by applications to provide custom encryption.
Definition wiredtiger.in:4558
Table of WiredTiger extension methods.
Definition wiredtiger_ext.h:58
#define WT_ERROR
Non-specific WiredTiger error.
Definition wiredtiger.in:4133
The configuration information returned by the WiredTiger configuration parsing functions in the WT_EX...
Definition wiredtiger.in:3827
const char * str
The value of a configuration string.
Definition wiredtiger.in:3838
size_t len
The number of bytes in the value referenced by str.
Definition wiredtiger.in:3841
A connection to a WiredTiger database.
Definition wiredtiger.in:2106
int add_encryptor(WT_CONNECTION *connection, const char *name, WT_ENCRYPTOR *encryptor, const char *config)
Add an encryption function.
WT_EXTENSION_API * get_extension_api(WT_CONNECTION *wt_conn)
Return a reference to the WiredTiger extension functions.
All data operations are performed in the context of a WT_SESSION.
Definition wiredtiger.in:822