mirror of
https://github.com/status-im/sqlcipher.git
synced 2025-02-23 17:28:17 +00:00
baseline working encryption plugin and build rules (hex key only)
This commit is contained in:
parent
617ed01e77
commit
11dd40da8d
202
src/crypto.c
Normal file
202
src/crypto.c
Normal file
@ -0,0 +1,202 @@
|
||||
/* BEGIN CRYPTO */
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "btreeInt.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "crypto.h"
|
||||
|
||||
typedef struct {
|
||||
int key_sz;
|
||||
Btree *pBt;
|
||||
void *key;
|
||||
void *rand;
|
||||
char *pKey;
|
||||
void *buffer;
|
||||
} codec_ctx;
|
||||
|
||||
static int codec_hash(codec_ctx *ctx, void *out, int *outLen, void *in, int inLen) {
|
||||
EVP_MD_CTX mdctx;
|
||||
unsigned int md_sz;
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
|
||||
EVP_MD_CTX_init(&mdctx);
|
||||
EVP_DigestInit_ex(&mdctx, DIGEST, NULL);
|
||||
|
||||
if(ctx->rand)
|
||||
EVP_DigestUpdate(&mdctx, ctx->rand, 16);
|
||||
|
||||
EVP_DigestUpdate(&mdctx, in, inLen);
|
||||
EVP_DigestFinal_ex(&mdctx, md_value, &md_sz);
|
||||
|
||||
memcpy(out, md_value, md_sz);
|
||||
|
||||
EVP_MD_CTX_cleanup(&mdctx);
|
||||
memset(md_value, 0, md_sz);
|
||||
*outLen = md_sz;
|
||||
}
|
||||
|
||||
/*
|
||||
* ctx - codec context
|
||||
* pgno - page number in database
|
||||
* size - size in bytes of input and output buffers
|
||||
* mode - 1 to encrypt, 0 to decrypt
|
||||
* in - pointer to input bytes
|
||||
* out - pouter to output bytes
|
||||
*/
|
||||
static int codec_cipher(codec_ctx *ctx, int pgno, int mode, int size, void *in, void *out) {
|
||||
EVP_CIPHER_CTX ectx;
|
||||
unsigned char iv[EVP_MAX_MD_SIZE];
|
||||
int iv_sz, tmp_csz, csz;
|
||||
|
||||
codec_hash(ctx, iv, &iv_sz, &pgno, sizeof(pgno));
|
||||
|
||||
EVP_CipherInit(&ectx, CIPHER, NULL, NULL, mode);
|
||||
EVP_CIPHER_CTX_set_padding(&ectx, 0);
|
||||
EVP_CipherInit(&ectx, NULL, ctx->key, iv, mode);
|
||||
EVP_CipherUpdate(&ectx, out, &tmp_csz, in, size);
|
||||
csz = tmp_csz;
|
||||
out += tmp_csz;
|
||||
EVP_CipherFinal(&ectx, out, &tmp_csz);
|
||||
csz += tmp_csz;
|
||||
EVP_CIPHER_CTX_cleanup(&ectx);
|
||||
assert(size == csz);
|
||||
}
|
||||
|
||||
|
||||
void sqlite3_activate_see(const char* in) {
|
||||
/* do nothing, security enhancements are always active */
|
||||
}
|
||||
|
||||
/*
|
||||
* sqlite3Codec can be called in multiple modes.
|
||||
* encrypt mode - expected to return a pointer to the
|
||||
* encrypted data without altering pData.
|
||||
* decrypt mode - expected to return a pointer to pData, with
|
||||
* the data decrypted in the input buffer
|
||||
*/
|
||||
void* sqlite3Codec(void *iCtx, void *pData, Pgno pgno, int mode) {
|
||||
int emode;
|
||||
codec_ctx *ctx = (codec_ctx *) iCtx;
|
||||
int pg_sz = sqlite3BtreeGetPageSize(ctx->pBt);
|
||||
|
||||
switch(mode) {
|
||||
case 0: /* decrypt */
|
||||
case 2:
|
||||
case 3:
|
||||
emode = 0;
|
||||
break;
|
||||
case 6: /* encrypt */
|
||||
case 7:
|
||||
emode = 1;
|
||||
break;
|
||||
default:
|
||||
return pData;
|
||||
break;
|
||||
}
|
||||
|
||||
if(pgno == 1 ) {
|
||||
/* duplicate first 24 bytes of page 1 exactly to include random header data and page size */
|
||||
memcpy(ctx->buffer, pData, HDR_SZ);
|
||||
|
||||
/* if this is a read & decrypt operation on the first page then copy the
|
||||
first 16 bytes off the page into the context's random salt buffer
|
||||
*/
|
||||
if(emode) {
|
||||
memcpy(ctx->buffer, ctx->rand, 16);
|
||||
} else {
|
||||
memcpy(ctx->rand, pData, 16);
|
||||
memcpy(ctx->buffer, SQLITE_FILE_HEADER, 16);
|
||||
}
|
||||
|
||||
/* adjust starting pointers in data page for header offset */
|
||||
codec_cipher(ctx, pgno, emode, pg_sz - HDR_SZ, &pData[HDR_SZ], &ctx->buffer[HDR_SZ]);
|
||||
} else {
|
||||
codec_cipher(ctx, pgno, emode, pg_sz, pData, ctx->buffer);
|
||||
}
|
||||
|
||||
if(emode) {
|
||||
return ctx->buffer; /* return persistent buffer data, pData remains intact */
|
||||
} else {
|
||||
memcpy(pData, ctx->buffer, pg_sz); /* copy buffer data back to pData and return */
|
||||
return pData;
|
||||
}
|
||||
}
|
||||
|
||||
int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
|
||||
void *keyd;
|
||||
int len;
|
||||
char hout[1024];
|
||||
struct Db *pDb = &db->aDb[nDb];
|
||||
|
||||
if(nKey && zKey && pDb->pBt) {
|
||||
codec_ctx *ctx;
|
||||
int rc;
|
||||
MemPage *pPage1;
|
||||
|
||||
ctx = sqlite3_malloc(sizeof(codec_ctx));
|
||||
|
||||
ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
|
||||
|
||||
/* assign random salt data. This will be written to the first page
|
||||
if this is a new database file. If an existing database file is
|
||||
attached this will just be overwritten when the first page is
|
||||
read from disk */
|
||||
ctx->rand = sqlite3_malloc(16);
|
||||
RAND_pseudo_bytes(ctx->rand, 16);
|
||||
|
||||
|
||||
/* pre-allocate a page buffer of PageSize bytes. This will
|
||||
be used as a persistent buffer for encryption and decryption
|
||||
operations to avoid overhead of multiple memory allocations*/
|
||||
ctx->buffer = sqlite3_malloc(sqlite3BtreeGetPageSize(ctx->pBt));
|
||||
|
||||
/* if key string starts with x' then this is a blob literal key*/
|
||||
if(sqlite3StrNICmp(zKey,"x'", 2) == 0) {
|
||||
int n = nKey - 3; /* adjust for leading x' and tailing ' */
|
||||
const char *z = zKey + 2; /* adjust lead offset of x' */
|
||||
ctx->key_sz = EVP_CIPHER_key_length(CIPHER);
|
||||
ctx->key = sqlite3HexToBlob(db, z, n);
|
||||
}
|
||||
|
||||
sqlite3pager_set_codec(sqlite3BtreePager(pDb->pBt), sqlite3Codec, (void *) ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
|
||||
if(db) {
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
sqlite3CodecAttach(db, i, pKey, nKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME - this should change the password for the database! */
|
||||
int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
|
||||
printf("sorry sqlite3_rekey is not implemented yet\n");
|
||||
sqlite3_key(db, pKey, nKey);
|
||||
}
|
||||
|
||||
void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
|
||||
extern int sqlite3pager_get_codec(Pager *pPager, void * ctx);
|
||||
codec_ctx *ctx;
|
||||
struct Db *pDb = &db->aDb[nDb];
|
||||
|
||||
if( pDb->pBt ) {
|
||||
sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
|
||||
if(ctx) {
|
||||
*zKey = ctx->key;
|
||||
*nKey = ctx->key_sz;
|
||||
} else {
|
||||
*zKey = 0;
|
||||
*nKey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
/* END CRYPTO */
|
18
src/crypto.h
Normal file
18
src/crypto.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
** crypto.h developed by Stephen Lombardo (Zetetic LLC)
|
||||
** sjlombardo at zetetic dot net
|
||||
** http://zetetic.net
|
||||
**
|
||||
*/
|
||||
/* BEGIN CRYPTO */
|
||||
#ifndef CRYPTO_H
|
||||
#define CRYPTO_H
|
||||
|
||||
#define CIPHER EVP_aes_256_cfb()
|
||||
#define DIGEST EVP_sha1()
|
||||
|
||||
/* HDR_SIZE allocates 16 bytes for random salt and 8 bytes for page size */
|
||||
#define HDR_SZ 24
|
||||
|
||||
#endif
|
||||
/* END CRYPTO */
|
Loading…
x
Reference in New Issue
Block a user