Shows how to extend WiredTiger with a simple encryption algorithm.
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include "windows_shim.h"
#endif
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
#ifdef _WIN32
__declspec(dllexport)
#endif
static const char *home = NULL;
#define SYS_KEYID "system"
#define SYS_PW "system_password"
#define USER1_KEYID "user1"
#define USER2_KEYID "user2"
#define USERBAD_KEYID "userbad"
#define ITEM_MATCHES(config_item, s) \
(strlen(s) == (config_item).len && \
strncmp((config_item).str, s, (config_item).len) == 0)
typedef struct {
int rot_N;
uint32_t num_calls;
char *keyid;
char *password;
} MY_CRYPTO;
#define CHKSUM_LEN 4
#define IV_LEN 16
static void
make_cksum(uint8_t *dst)
{
int i;
for (i = 0; i < CHKSUM_LEN; i++)
dst[i] = 'C';
}
static void
make_iv(uint8_t *dst)
{
int i;
for (i = 0; i < IV_LEN; i++)
dst[i] = 'I';
}
static void
do_rotate(char *buf, size_t len, int rotn)
{
uint32_t i;
for (i = 0; i < len; i++)
if (isalpha(buf[i])) {
if (islower(buf[i]))
buf[i] = ((buf[i] - 'a') + rotn) % 26 + 'a';
else
buf[i] = ((buf[i] - 'A') + rotn) % 26 + 'A';
}
}
static int
uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_len,
size_t *result_lenp)
{
MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor;
size_t mylen;
uint32_t i;
(void)session;
++my_crypto->num_calls;
if (src == NULL)
return (0);
mylen = src_len - (CHKSUM_LEN + IV_LEN);
if (dst_len < mylen) {
fprintf(stderr,
"Rotate: ENOMEM ERROR: dst_len %zu src_len %zu\n",
dst_len, src_len);
return (ENOMEM);
}
i = CHKSUM_LEN + IV_LEN;
memcpy(&dst[0], &src[i], mylen);
do_rotate((char *)dst, mylen, 26 - my_crypto->rot_N);
*result_lenp = mylen;
return (0);
}
static int
uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_len,
size_t *result_lenp)
{
MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor;
uint32_t i;
(void)session;
++my_crypto->num_calls;
if (src == NULL)
return (0);
if (dst_len < src_len + CHKSUM_LEN + IV_LEN)
return (ENOMEM);
i = CHKSUM_LEN + IV_LEN;
memcpy(&dst[i], &src[0], src_len);
do_rotate((char *)dst + i, src_len, my_crypto->rot_N);
i = 0;
make_cksum(&dst[i]);
i += CHKSUM_LEN;
make_iv(&dst[i]);
*result_lenp = dst_len;
return (0);
}
static int
size_t *expansion_constantp)
{
MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor;
(void)session;
++my_crypto->num_calls;
*expansion_constantp = CHKSUM_LEN + IV_LEN;
return (0);
}
static int
{
MY_CRYPTO *my_crypto;
int ret;
const MY_CRYPTO *orig_crypto;
orig_crypto = (const MY_CRYPTO *)encryptor;
if ((my_crypto = calloc(1, sizeof(MY_CRYPTO))) == NULL) {
ret = errno;
goto err;
}
*my_crypto = *orig_crypto;
my_crypto->keyid = my_crypto->password = NULL;
if ((ret = extapi->
config_get(extapi, session, encrypt_config,
"keyid", &keyid)) == 0 && keyid.
len != 0) {
if ((my_crypto->keyid = malloc(keyid.
len + 1)) == NULL) {
ret = errno;
goto err;
}
strncpy(my_crypto->keyid, keyid.
str, keyid.
len + 1);
my_crypto->keyid[keyid.
len] =
'\0';
}
if ((ret = extapi->
config_get(extapi, session, encrypt_config,
"secretkey", &secret)) == 0 && secret.
len != 0) {
if ((my_crypto->password = malloc(secret.
len + 1)) == NULL) {
ret = errno;
goto err;
}
strncpy(my_crypto->password, secret.
str, secret.
len + 1);
my_crypto->password[secret.
len] =
'\0';
}
if (ITEM_MATCHES(keyid, "system")) {
if (my_crypto->password == NULL ||
strcmp(my_crypto->password, SYS_PW) != 0) {
ret = EPERM;
goto err;
}
my_crypto->rot_N = 13;
} else if (ITEM_MATCHES(keyid, USER1_KEYID))
my_crypto->rot_N = 4;
else if (ITEM_MATCHES(keyid, USER2_KEYID))
my_crypto->rot_N = 19;
else {
ret = EINVAL;
goto err;
}
++my_crypto->num_calls;
return (0);
err: free(my_crypto->keyid);
free(my_crypto->password);
free(my_crypto);
return (ret);
}
static int
{
MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor;
(void)session;
++my_crypto->num_calls;
free(my_crypto->password);
my_crypto->password = NULL;
free(my_crypto->keyid);
my_crypto->keyid = NULL;
free(encryptor);
return (0);
}
int
{
MY_CRYPTO *m;
int ret;
if ((m = calloc(1, sizeof(MY_CRYPTO))) == NULL)
return (errno);
m->num_calls = 0;
return (ret);
return (0);
}
static int
{
uint64_t txnid;
uint32_t fileid, opcount, optype, rectype;
int found, ret;
ret = session->
open_cursor(session,
"log:", NULL, NULL, &cursor);
found = 0;
while ((ret = cursor->
next(cursor)) == 0) {
&rectype, &optype, &fileid, &logrec_key, &logrec_value);
found = 1;
printf("Application Log Record: %s\n",
(
char *)logrec_value.
data);
}
}
ret = 0;
ret = cursor->
close(cursor);
if (found == 0) {
fprintf(stderr, "Did not find log messages.\n");
exit(EXIT_FAILURE);
}
return (ret);
}
#define MAX_KEYS 20
#define EXTENSION_NAME "local=(entry=add_my_encryptors)"
#define WT_OPEN_CONFIG_COMMON \
"create,cache_size=100MB,extensions=[" EXTENSION_NAME "],"\
"log=(archive=false,enabled=true)," \
#define WT_OPEN_CONFIG_GOOD \
WT_OPEN_CONFIG_COMMON \
"encryption=(name=rotn,keyid=" SYS_KEYID ",secretkey=" SYS_PW ")"
#define COMP_A "AAAAAAAAAAAAAAAAAA"
#define COMP_B "BBBBBBBBBBBBBBBBBB"
#define COMP_C "CCCCCCCCCCCCCCCCCC"
int
main(void)
{
int i, ret;
char keybuf[16], valbuf[16];
char *key1, *key2, *key3, *val1, *val2, *val3;
if (getenv("WIREDTIGER_HOME") == NULL) {
home = "WT_HOME";
ret = system("rm -rf WT_HOME && mkdir WT_HOME");
} else
home = NULL;
COMP_A COMP_B COMP_C COMP_A COMP_B COMP_C
COMP_A COMP_B COMP_C COMP_A COMP_B COMP_C
"The quick brown fox jumps over the lazy dog ");
ret = simple_walk_log(session);
ret = session->
create(session,
"table:crypto1",
"encryption=(name=rotn,keyid=" USER1_KEYID"),"
"columns=(key0,value0),"
"key_format=S,value_format=S");
ret = session->
create(session,
"index:crypto1:byvalue",
"encryption=(name=rotn,keyid=" USER1_KEYID"),"
"columns=(value0,key0)");
ret = session->
create(session,
"table:crypto2",
"encryption=(name=rotn,keyid=" USER2_KEYID"),"
"key_format=S,value_format=S");
ret = session->
create(session,
"table:nocrypto",
"key_format=S,value_format=S");
ret = session->
create(session,
"table:cryptobad",
"encryption=(name=rotn,keyid=" USERBAD_KEYID"),"
"key_format=S,value_format=S");
if (ret == 0) {
fprintf(stderr, "Did not detect bad/unknown keyid error\n");
exit(EXIT_FAILURE);
}
ret = session->
open_cursor(session,
"table:crypto1", NULL, NULL, &c1);
ret = session->
open_cursor(session,
"table:crypto2", NULL, NULL, &c2);
ret = session->
open_cursor(session,
"table:nocrypto", NULL, NULL, &nc);
for (i = 0; i < MAX_KEYS; i++) {
snprintf(keybuf, sizeof(keybuf), "key%d", i);
snprintf(valbuf, sizeof(valbuf), "value%d", i);
if (i % 5 == 0)
"Wrote %d records", i);
}
ret = session->
log_printf(session,
"Done. Wrote %d total records", i);
while (c1->
next(c1) == 0) {
printf("Read key %s; value %s\n", key1, val1);
}
ret = simple_walk_log(session);
printf("CLOSE\n");
ret = conn->
close(conn, NULL);
printf("REOPEN and VERIFY encrypted data\n");
ret = simple_walk_log(session);
ret = session->
open_cursor(session,
"table:crypto1", NULL, NULL, &c1);
ret = session->
open_cursor(session,
"table:crypto2", NULL, NULL, &c2);
ret = session->
open_cursor(session,
"table:nocrypto", NULL, NULL, &nc);
while (c1->
next(c1) == 0) {
if (strcmp(key1, key2) != 0)
fprintf(stderr, "Key1 %s and Key2 %s do not match\n",
key1, key2);
if (strcmp(key1, key3) != 0)
fprintf(stderr, "Key1 %s and Key3 %s do not match\n",
key1, key3);
if (strcmp(key2, key3) != 0)
fprintf(stderr, "Key2 %s and Key3 %s do not match\n",
key2, key3);
if (strcmp(val1, val2) != 0)
fprintf(stderr, "Val1 %s and Val2 %s do not match\n",
val1, val2);
if (strcmp(val1, val3) != 0)
fprintf(stderr, "Val1 %s and Val3 %s do not match\n",
val1, val3);
if (strcmp(val2, val3) != 0)
fprintf(stderr, "Val2 %s and Val3 %s do not match\n",
val2, val3);
printf("Verified key %s; value %s\n", key1, val1);
}
ret = conn->
close(conn, NULL);
return (ret);
}