A newer version of this documentation is available.

View Latest

Field Level Encryption from the C SDK

    +
    Field Level Encryption is available in Couchbase Data Platform 5.5, from C SDK (Libcouchbase) version 2.8.6.

    Test Sample

    Here is a brief example of the code to encrypt a field using libcouchbase, the C SDK.

    Sample Code

    Encrypt
    static void store_encrypted(lcb_t instance, const char *key, const char *val)
    {
        lcb_error_t err;
        lcb_CMDSTORE cmd = {};
        lcbcrypto_CMDENCRYPT ecmd = {};
        lcbcrypto_FIELDSPEC field = {};
    
        printf("KEY:    %s\n", key);
        printf("PLAIN:  %s\n", val);
    
        ecmd.version = 0;
        ecmd.prefix = NULL;
        ecmd.doc = val;
        ecmd.ndoc = strlen(val);
        ecmd.out = NULL;
        ecmd.nout = 0;
        ecmd.nfields = 1;
        ecmd.fields = &field;
        field.name = "message";
        field.alg = "AES-256-HMAC-SHA256";
        field.kid = "mypublickey";
    
        err = lcbcrypto_encrypt_document(instance, &ecmd);
        if (err != LCB_SUCCESS) {
            die(instance, "Couldn't encrypt field 'message'", err);
        }
        printf("CIPHER: %s\n", ecmd.out);
    
        LCB_CMD_SET_KEY(&cmd, key, strlen(key));
        LCB_CMD_SET_VALUE(&cmd, ecmd.out, ecmd.nout);
        cmd.operation = LCB_SET;
        cmd.datatype = LCB_DATATYPE_JSON;
    
        err = lcb_store3(instance, NULL, &cmd);
        free(ecmd.out); // NOTE: it should be compatible with what providers use to allocate memory
        if (err != LCB_SUCCESS) {
            die(instance, "Couldn't schedule storage operation", err);
        }
        lcb_wait(instance);
    }

    To decrypt the data again, use the following:

    Decrypt
    static void get_callback(lcb_t instance, int cbtype, const lcb_RESPBASE *rb)
    {
        if (rb->rc == LCB_SUCCESS) {
            const lcb_RESPGET *rg = (const lcb_RESPGET *)rb;
            lcbcrypto_CMDDECRYPT dcmd = {};
            lcb_error_t err;
    
            printf("VALUE:  %.*s\n", (int)rg->nvalue, rg->value);
            dcmd.version = 0;
            dcmd.prefix = NULL;
            dcmd.doc = rg->value;
            dcmd.ndoc = rg->nvalue;
            dcmd.out = NULL;
            dcmd.nout = 0;
            err = lcbcrypto_decrypt_document(instance, &dcmd);
            if (err != LCB_SUCCESS) {
                die(instance, "Couldn't decrypt field 'message'", err);
            }
            if (dcmd.out == NULL) {
                die(instance, "Crypto provider returned success, but document is NULL", LCB_EINVAL);
            }
            printf("PLAIN:  %.*s\n", (int)dcmd.nout, dcmd.out);
            free(dcmd.out); // NOTE: it should be compatible with what providers use to allocate memory
            printf("CAS:    0x%" PRIx64 "\n", rb->cas);
        } else {
            die(instance, lcb_strcbtype(cbtype), rb->rc);
        }
    }
    
    static void get_encrypted(lcb_t instance, const char *key)
    {
        lcb_CMDGET cmd = {};
        lcb_error_t err;
        LCB_CMD_SET_KEY(&cmd, key, strlen(key));
        printf("KEY:    %s\n", key);
        err = lcb_get3(instance, NULL, &cmd);
        if (err != LCB_SUCCESS) {
            die(instance, "Couldn't schedule get operation", err);
        }
        lcb_wait(instance);
    }