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;
#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_checksum(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((unsigned char)buf[i])) {
                        if (islower((unsigned char)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_checksum(&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, log_file, log_offset, opcount, optype, rectype;
        int found, ret;
        ret = session->
open_cursor(session, 
"log:", NULL, NULL, &cursor);
        found = 0;
        while ((ret = cursor->
next(cursor)) == 0) {
 
                ret = cursor->
get_key(cursor, &log_file, &log_offset, &opcount);
                    &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++) {
                (void)snprintf(keybuf, sizeof(keybuf), "key%d", i);
                (void)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 == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}